/*
 * Copyright OpenSearch Contributors
 * SPDX-License-Identifier: Apache-2.0
 */

import { i18n } from '@osd/i18n';
import {
  EmbeddableFactoryDefinition,
  EmbeddableOutput,
  ErrorEmbeddable,
  IContainer,
  SavedObjectEmbeddableInput,
} from '../../../embeddable/public';
import { VISUALIZE_ENABLE_LABS_SETTING } from '../../../visualizations/public';
import {
  EDIT_PATH,
  PLUGIN_ID,
  PLUGIN_NAME,
  VisBuilderSavedObjectAttributes,
  VISBUILDER_SAVED_OBJECT,
} from '../../common';
import { DisabledEmbeddable } from './disabled_embeddable';
import {
  VisBuilderEmbeddable,
  VisBuilderInput,
  VisBuilderOutput,
  VISBUILDER_EMBEDDABLE,
} from './vis_builder_embeddable';
import { getStateFromSavedObject } from '../saved_visualizations/transforms';
import {
  getHttp,
  getSavedVisBuilderLoader,
  getTimeFilter,
  getUISettings,
} from '../plugin_services';
import { StartServicesGetter } from '../../../opensearch_dashboards_utils/public';
import { VisBuilderPluginStartDependencies } from '../types';

export interface VisBuilderEmbeddableFactoryDeps {
  start: StartServicesGetter<VisBuilderPluginStartDependencies>;
}

export class VisBuilderEmbeddableFactory
  implements
    EmbeddableFactoryDefinition<
      SavedObjectEmbeddableInput,
      VisBuilderOutput | EmbeddableOutput,
      VisBuilderEmbeddable | DisabledEmbeddable,
      VisBuilderSavedObjectAttributes
    > {
  public readonly type = VISBUILDER_EMBEDDABLE;
  public readonly savedObjectMetaData = {
    // TODO: Update to include most vis functionality
    name: PLUGIN_NAME,
    includeFields: ['visualizationState'],
    type: VISBUILDER_SAVED_OBJECT,
    getIconForSavedObject: () => 'visBuilder',
  };

  // TODO: Would it be better to explicitly declare start service dependencies?
  constructor(private readonly deps: VisBuilderEmbeddableFactoryDeps) {}

  public canCreateNew() {
    // Because VisBuilder creation starts with the visualization modal, no need to have a separate entry for VisBuilder until it's separate
    return false;
  }

  public async isEditable() {
    // TODO: Add proper access controls
    // return getCapabilities().visualize.save as boolean;
    return true;
  }

  public async createFromSavedObject(
    savedObjectId: string,
    input: VisBuilderInput,
    parent?: IContainer
  ): Promise<VisBuilderEmbeddable | ErrorEmbeddable | DisabledEmbeddable> {
    try {
      const savedObject = await getSavedVisBuilderLoader().get(savedObjectId);
      const editPath = `${EDIT_PATH}/${savedObjectId}`;
      const editUrl = getHttp().basePath.prepend(`/app/${PLUGIN_ID}${editPath}`);
      const isLabsEnabled = getUISettings().get<boolean>(VISUALIZE_ENABLE_LABS_SETTING);

      if (!isLabsEnabled) {
        return new DisabledEmbeddable(PLUGIN_NAME, input);
      }

      const savedVis = getStateFromSavedObject(savedObject);
      const indexPatternService = this.deps.start().plugins.data.indexPatterns;
      const indexPattern = await indexPatternService.get(
        savedVis.state.visualization.indexPattern || ''
      );
      const indexPatterns = indexPattern ? [indexPattern] : [];

      return new VisBuilderEmbeddable(
        getTimeFilter(),
        {
          savedVis,
          editUrl,
          editPath,
          editable: true,
          deps: this.deps,
          indexPatterns,
        },
        {
          ...input,
          savedObjectId: input.savedObjectId ?? '',
        },
        {
          parent,
        }
      );
    } catch (e) {
      console.error(e); // eslint-disable-line no-console
      return new ErrorEmbeddable(e as Error, input, parent);
    }
  }

  public async create(_input: SavedObjectEmbeddableInput, _parent?: IContainer) {
    return undefined;
  }

  public getDisplayName() {
    return i18n.translate('visBuilder.displayName', {
      defaultMessage: PLUGIN_ID,
    });
  }
}