import { action, computed, makeObservable, observable } from 'mobx';
import { CustomFieldsFormState } from './CustomFieldsFormState';
import { CustomFieldsWidgetState } from './CustomFieldsWidgetState';
import orderBy from 'lodash/orderBy';
import { DataExtensionField } from '@wix/bex-core';

export interface CustomFieldsAllNamespacesFormStateParams {
  customFieldsWidgetState: CustomFieldsWidgetState;
}

export class CustomFieldsAllNamespacesFormState {
  readonly _customFieldsWidgetState;

  readonly namespacesFormsMap = observable.map<string, CustomFieldsFormState>(
    [],
    {
      deep: false,
    },
  );

  constructor(params: CustomFieldsAllNamespacesFormStateParams) {
    this._customFieldsWidgetState = params.customFieldsWidgetState;
    makeObservable(this, {
      namespacesForms: computed,
      addFormIfAbsent: action,
      validate: action,
      isDirty: computed,
      schemasSections: computed,
      tpaFieldsExist: computed,
    });
  }

  get schemasSections() {
    const {
      _customFieldsWidgetState: {
        dataExtension: { _dataExtensionSchemas },
        _userFieldsNamespace,
      },
    } = this;
    const schemasWithEditableProps = _dataExtensionSchemas.filter(
      (schema) =>
        schema.jsonSchema?.properties &&
        Object.keys(schema.jsonSchema.properties).length > 0 &&
        (schema.namespace === _userFieldsNamespace ||
          Object.values(
            schema.jsonSchema.properties as Record<string, DataExtensionField>,
          ).some(
            (prop) =>
              prop['x-wix-permissions']?.write?.includes('users') &&
              prop['x-wix-permissions']?.read?.includes('users'),
          )),
    );
    return orderBy(
      schemasWithEditableProps,
      [
        (s) => (s.namespace === _userFieldsNamespace ? 1 : 0),
        (s) => s.createdDate,
      ],
      ['desc', 'desc'],
    );
  }

  get tpaFieldsExist() {
    const {
      schemasSections,
      _customFieldsWidgetState: { _userFieldsNamespace },
    } = this;
    return schemasSections.some(
      (schema) => schema.namespace !== _userFieldsNamespace,
    );
  }

  getNamespaceFormSchemaAndData(namespace: string) {
    const { _customFieldsWidgetState: state } = this;
    const { schema, fields } =
      state.dataExtension.getSchemaAndFieldsByNamespace(namespace);

    return {
      fields,
      schema,
      extendedFieldsDataMap: state._extendedFields?.namespaces?.[namespace],
    };
  }

  get namespacesForms() {
    return Array.from(this.namespacesFormsMap.values());
  }

  addFormIfAbsent(form: CustomFieldsFormState) {
    const { namespacesFormsMap } = this;

    const maybeForm = namespacesFormsMap.get(form._namespace) ?? form;

    namespacesFormsMap.set(form._namespace, maybeForm);

    return maybeForm;
  }

  validate() {
    const {
      namespacesFormsMap,
      _customFieldsWidgetState: { _userFieldsNamespace },
    } = this;
    const resultsMap = new Map(
      Array.from(namespacesFormsMap.values()).map((form) => [
        form._namespace,
        form.validate(),
      ]),
    );

    const results = Array.from(resultsMap.values());

    const extendedFields = Object.fromEntries(
      Array.from(resultsMap.entries()).map(([namespace, result]) => [
        namespace,
        result.extendedFields,
      ]),
    );

    return {
      isValid: results.every((result) => result.isValid),
      extendedFields: {
        namespaces: {
          [_userFieldsNamespace]: {},
          ...extendedFields,
        },
      },
    };
  }

  get isDirty() {
    const { namespacesForms } = this;
    return namespacesForms.some((form) => form.isDirty);
  }
}
