/**
 * Copyright (c) 2020-present, Goldman Sachs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import packageJson from '../../package.json' with { type: 'json' };
import {
  type DSL_LegendStudioApplicationPlugin_Extension,
  type EditorStore,
  type ElementClassifier,
  type ElementEditorRenderer,
  type ElementEditorState,
  type ElementEditorStateCreator,
  type ElementIconGetter,
  type ElementTypeLabelGetter,
  type NewElementDriver,
  type NewElementDriverCreator,
  type NewElementDriverEditorRenderer,
  type NewElementFromStateCreator,
  type NewElementState,
  LegendStudioApplicationPlugin,
  PACKAGEABLE_ELEMENT_GROUP_BY_CATEGORY,
} from '@finos/legend-application-studio';
import type { PackageableElement } from '@finos/legend-graph';
import {
  DataQualityClassValidationsConfiguration,
  DataQualityServiceValidationConfiguration,
  DataQualityRelationValidationConfiguration,
  DataQualityValidationConfiguration,
  DataQualityRelationComparisonConfiguration,
  DataQualityRelationQueryLambda,
  MD5HashStrategy,
} from '../graph/metamodel/pure/packageableElements/data-quality/DataQualityValidationConfiguration.js';
import { CompareIcon, EyeIcon } from '@finos/legend-art';
import { DataQualityClassValidationEditor } from './DataQualityClassValidationEditor.js';
import { DataQuality_ElementDriver } from './DSL_DataQuality_ElementDriver.js';
import { DataQualityServiceValidationEditor } from './DataQualityServiceValidationEditor.js';
import { DataQualityClassValidationState } from './states/DataQualityClassValidationState.js';
import { NewDataQualityValidationElementEditor } from './DSL_NewDataQualityValidationElement.js';
import { DataQualityServiceValidationState } from './states/DataQualityServiceValidationState.js';
import { DataQualityRelationValidationConfigurationState } from './states/DataQualityRelationValidationConfigurationState.js';
import { DataQualityRelationValidationConfigurationEditor } from './DataQualityRelationValidationConfigurationEditor.js';
import { DSL_DATA_QUALITY_LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY } from '../__lib__/studio/DSL_DataQuality_LegendStudioApplicationNavigationContext.js';
import { DataQualityRelationComparisonConfigurationState } from './states/DataQualityRelationComparisonConfigurationState.js';
import { DataQualityRelationComparisonEditor } from './DataQualityRelationComparisonEditor.js';

const DATA_QUALITY_VALIDATION_ELEMENT_TYPE = 'DATAQUALITYVALIDATION';
const DATA_QUALITY_VALIDATION_ELEMENT_TYPE_LABEL = 'Data Quality Validation';

const DATA_QUALITY_RELATION_COMPARISON_ELEMENT_TYPE =
  'DATAQUALITYRELATIONCOMPARISON';
const DATA_QUALITY_RELATION_COMPARISON_ELEMENT_TYPE_LABEL =
  'Data Quality Relation Comparison';

export class DSL_DataQuality_LegendStudioApplicationPlugin
  extends LegendStudioApplicationPlugin
  implements DSL_LegendStudioApplicationPlugin_Extension
{
  constructor() {
    super(packageJson.extensions.applicationStudioPlugin, packageJson.version);
  }

  getExtraSupportedElementTypes(): string[] {
    return [
      DATA_QUALITY_VALIDATION_ELEMENT_TYPE,
      DATA_QUALITY_RELATION_COMPARISON_ELEMENT_TYPE,
    ];
  }

  getExtraSupportedElementTypesWithCategory(): Map<string, string[]> {
    const elementTypeswithCategory = new Map<string, string[]>();
    elementTypeswithCategory.set(PACKAGEABLE_ELEMENT_GROUP_BY_CATEGORY.OTHER, [
      DATA_QUALITY_VALIDATION_ELEMENT_TYPE,
      DATA_QUALITY_RELATION_COMPARISON_ELEMENT_TYPE,
    ]);
    return elementTypeswithCategory;
  }

  getExtraElementClassifiers(): ElementClassifier[] {
    return [
      (element: PackageableElement): string | undefined => {
        if (element instanceof DataQualityValidationConfiguration) {
          return DATA_QUALITY_VALIDATION_ELEMENT_TYPE;
        }
        if (element instanceof DataQualityRelationComparisonConfiguration) {
          return DATA_QUALITY_RELATION_COMPARISON_ELEMENT_TYPE;
        }
        return undefined;
      },
    ];
  }

  getExtraElementIconGetters(): ElementIconGetter[] {
    return [
      (type: string): React.ReactNode | undefined => {
        if (type === DATA_QUALITY_VALIDATION_ELEMENT_TYPE) {
          return (
            <div className="icon icon--dataQuality">
              <EyeIcon />
            </div>
          );
        } else if (type === DATA_QUALITY_RELATION_COMPARISON_ELEMENT_TYPE) {
          return (
            <div className="icon icon--dataQuality">
              <CompareIcon />
            </div>
          );
        }
        return undefined;
      },
    ];
  }

  getExtraElementTypeLabelGetters(): ElementTypeLabelGetter[] {
    return [
      (type: string): string | undefined => {
        if (type === DATA_QUALITY_VALIDATION_ELEMENT_TYPE) {
          return DATA_QUALITY_VALIDATION_ELEMENT_TYPE_LABEL;
        }
        if (type === DATA_QUALITY_RELATION_COMPARISON_ELEMENT_TYPE) {
          return DATA_QUALITY_RELATION_COMPARISON_ELEMENT_TYPE_LABEL;
        }
        return undefined;
      },
    ];
  }

  getExtraNewElementFromStateCreators(): NewElementFromStateCreator[] {
    return [
      (
        type: string,
        name: string,
        state: NewElementState,
      ): PackageableElement | undefined => {
        if (type === DATA_QUALITY_VALIDATION_ELEMENT_TYPE) {
          return state
            .getNewElementDriver(DataQuality_ElementDriver)
            .createElement(name);
        }
        if (type === DATA_QUALITY_RELATION_COMPARISON_ELEMENT_TYPE) {
          const comparison = new DataQualityRelationComparisonConfiguration(
            name,
          );
          comparison.source = new DataQualityRelationQueryLambda();
          comparison.target = new DataQualityRelationQueryLambda();
          // default currently
          comparison.strategy = new MD5HashStrategy();
          return comparison;
        }
        return undefined;
      },
    ];
  }

  getExtraElementEditorRenderers(): ElementEditorRenderer[] {
    return [
      (elementEditorState: ElementEditorState): React.ReactNode | undefined => {
        if (elementEditorState instanceof DataQualityServiceValidationState) {
          return (
            <DataQualityServiceValidationEditor key={elementEditorState.uuid} />
          );
        }
        if (elementEditorState instanceof DataQualityClassValidationState) {
          return (
            <DataQualityClassValidationEditor key={elementEditorState.uuid} />
          );
        }
        if (
          elementEditorState instanceof
          DataQualityRelationValidationConfigurationState
        ) {
          return (
            <DataQualityRelationValidationConfigurationEditor
              key={elementEditorState.uuid}
            />
          );
        }
        if (
          elementEditorState instanceof
          DataQualityRelationComparisonConfigurationState
        ) {
          return (
            <DataQualityRelationComparisonEditor
              key={elementEditorState.uuid}
            />
          );
        }
        return undefined;
      },
    ];
  }

  getExtraElementEditorStateCreators(): ElementEditorStateCreator[] {
    return [
      (
        editorStore: EditorStore,
        element: PackageableElement,
      ): ElementEditorState | undefined => {
        if (element instanceof DataQualityClassValidationsConfiguration) {
          return new DataQualityClassValidationState(editorStore, element);
        }
        if (element instanceof DataQualityServiceValidationConfiguration) {
          return new DataQualityServiceValidationState(editorStore, element);
        }
        if (element instanceof DataQualityRelationValidationConfiguration) {
          return new DataQualityRelationValidationConfigurationState(
            editorStore,
            element,
          );
        }
        if (element instanceof DataQualityRelationComparisonConfiguration) {
          return new DataQualityRelationComparisonConfigurationState(
            editorStore,
            element,
          );
        }
        return undefined;
      },
    ];
  }

  getExtraNewElementDriverEditorRenderers(): NewElementDriverEditorRenderer[] {
    return [
      (type: string): React.ReactNode | undefined => {
        if (type === DATA_QUALITY_VALIDATION_ELEMENT_TYPE) {
          return <NewDataQualityValidationElementEditor />;
        }
        return undefined;
      },
    ];
  }

  getExtraNewElementDriverCreators(): NewElementDriverCreator[] {
    return [
      (
        editorStore: EditorStore,
        type: string,
      ): NewElementDriver<PackageableElement> | undefined => {
        if (type === DATA_QUALITY_VALIDATION_ELEMENT_TYPE) {
          return new DataQuality_ElementDriver(editorStore);
        }
        return undefined;
      },
    ];
  }

  override getExtraAccessEventLoggingApplicationContextKeys(): string[] {
    return [
      DSL_DATA_QUALITY_LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY.LAMBDA_EDITOR,
      DSL_DATA_QUALITY_LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY.VALIDATION_ASSERTION_EDITOR,
    ];
  }
}
