import { action, makeObservable, observable } from 'mobx';
import { ConditionalModalState, type ToastConfig } from '@wix/bex-core';
import { Field, SchemaConfig } from '../../types/SchemaConfig';
import { CmsFormState } from './CmsFormState';
import { toFieldSpec } from './toFieldSpec';
import { getFieldTypeValidationRulesList } from './fieldValidationRulesMap';

export class CmsFieldModalState {
  private readonly getSchema: () => SchemaConfig;
  private readonly resolveError: (e: unknown) => ToastConfig;
  readonly modal: ConditionalModalState<null>;
  formState: CmsFormState | null = null;

  constructor(
    getSchema: () => SchemaConfig,
    resolveError: (e: unknown) => ToastConfig,
  ) {
    this.getSchema = getSchema;
    this.resolveError = resolveError;
    this.modal = new ConditionalModalState({
      onConfirm: () => this.submit(),
    });

    makeObservable(this, {
      formState: observable.ref,
      open: action,
      reset: action,
    });
  }

  open(fieldId?: string) {
    const schemaConfig = this.getSchema();

    this.formState = new CmsFormState({
      schemaConfig,
      getValidationRules: getFieldTypeValidationRulesList,
    });

    if (fieldId) {
      const field = schemaConfig.fields[fieldId];
      if (!field) {
        console.warn(`[CmsFieldModalState] Missing field "${fieldId}"`);
        return;
      }

      this.formState.setMode('edit');
      this.formState.loadField(field);
    }

    this.modal.open(null);
  }

  reset() {
    this.formState = null;
  }

  private async submit(): Promise<void> {
    const { formState } = this;
    if (!formState) {
      return;
    }
    const schemaConfig = this.getSchema();

    if (formState.hasInvalidFields || !formState.properties.type) {
      formState.enableShowValidationError();
      throw new Error('validation');
    }

    try {
      const { type, ...rest } = formState.properties;
      const fieldSpec = toFieldSpec({ ...rest, type }, formState.fieldRules);

      if (formState.mode === 'edit') {
        if (!formState.editingFieldId) {
          throw new Error('Missing editing field id for CMS field update');
        }
        if (!schemaConfig.fieldActions?.editField) {
          throw new Error(
            'SchemaConfig.fieldActions.editField is not configured',
          );
        }
        await schemaConfig.fieldActions.editField(
          formState.editingFieldId,
          fieldSpec,
        );
        schemaConfig.refresh?.();
        return;
      }

      if (!schemaConfig.fieldActions?.addField) {
        throw new Error('SchemaConfig.fieldActions.addField is not configured');
      }
      await schemaConfig.fieldActions.addField(fieldSpec as Field);
      schemaConfig.refresh?.();
    } catch (e) {
      formState.setErrorToastConfig(this.resolveError(e));
      throw e;
    }
  }
}
