import {
  addResizeObserver,
  AppsState,
  DataExtensionState,
  DefaultPermissionsConfig,
  ExtendedFields,
  Fqdn,
  fqdnToString,
  TaskState,
  WixPatternsContainer,
  WixPatternsError,
} from '@wix/bex-core';
import { SidePanelsState } from '../SidePanelsState';
import { action, computed, makeObservable, observable } from 'mobx';
import type * as CustomFieldsWidgetLazyContent from '../../components/CustomFieldsWidget/CustomFieldsWidgetLazyContent';
import {
  cairoErrorInLoadingAComponent,
  cairoTryAgainClicked,
  loadEnd,
  loadStart,
} from '@wix/bex-core/bi';

import { CustomFieldsAllNamespacesFormState } from './CustomFieldsAllNamespacesFormState';
import { CustomFieldsPanelState } from './CustomFieldsPanelState';

export interface CustomFieldsWidgetStateParams {
  readonly container: WixPatternsContainer;
  readonly fqdn: Fqdn;
  readonly filterable?: boolean;
  readonly containsPii?: boolean;
  readonly extendedFields?: ExtendedFields;
  readonly defaultPermissions?: DefaultPermissionsConfig;
  readonly enableArchive?: boolean;
}

export type CustomFieldsWidgetSize = 'default' | 'small';

export class CustomFieldsWidgetState {
  readonly container;
  readonly dataExtension;
  readonly initTask = new TaskState();

  _extendedFields: ExtendedFields | null | undefined = null;
  _formState: CustomFieldsAllNamespacesFormState | null = null;

  _size: CustomFieldsWidgetSize;
  _widgetContentRef: { current: HTMLDivElement | null } = {
    current: null,
  };

  readonly panels;
  readonly reportBi;
  readonly fqdn;
  _customFieldsLazyComponents:
    | typeof CustomFieldsWidgetLazyContent
    | undefined = undefined;

  readonly apps;
  readonly customFieldsPanel;

  constructor({
    container,
    fqdn,
    filterable,
    containsPii,
    defaultPermissions,
    extendedFields,
    enableArchive,
  }: CustomFieldsWidgetStateParams) {
    this.container = container;

    this.fqdn = fqdn;
    this._extendedFields = extendedFields;
    this._size = 'default';
    this.panels = new SidePanelsState({
      panelGroupName: fqdnToString(fqdn),
      container,
    });

    this.reportBi = container.createBILogger({
      componentType: 'CustomFieldsWidget',
      ...fqdn,
    });

    this.dataExtension = new DataExtensionState({
      container,
      fqdn,
      closeSidePanel: this.panels.closeSidePanel,
      filterable,
      containsPii,
      defaultPermissions,
      enableArchive,
    });

    this.apps = new AppsState({
      container,
      dataExtension: this.dataExtension,
    });

    this.customFieldsPanel = new CustomFieldsPanelState({
      dataExtension: this.dataExtension,
      reportBi: this.reportBi,
      closeSidePanel: this.panels.closeSidePanel,
    });

    makeObservable(this, {
      hasWritePermissions: computed,
      widgetSize: computed,
      setWidgetContentRef: action,
      isLoading: computed,
      isError: computed,
      _size: observable.ref,
      _widgetContentRef: observable.ref,
      _extendedFields: observable.ref,
      _adjustWidgetSize: action.bound,
      retry: action.bound,
    });
  }

  get _userFieldsNamespace() {
    return this.dataExtension.dataExtensionService.userFieldsNamespace;
  }

  _appLoadingStart() {
    const startTime = performance.now();
    const commonBiParams = this._commonDynamicBiParams();

    this.reportBi(
      loadStart({
        ...commonBiParams,
      }),
    );

    return () => {
      this.reportBi(
        loadEnd({
          ...commonBiParams,
          loadingTime: Math.round(performance.now() - startTime),
        }),
      );
    };
  }

  init({ appLoaded }: { appLoaded?: () => void }) {
    const { initTask, dataExtension, container, apps } = this;

    const disposers = [dataExtension.init(), apps.init()];

    initTask.runOnce(async () => {
      dataExtension.initTask.runOnce();
      apps.initTask.runOnce();

      const [lazyComponents] = await Promise.all([
        import(
          /* webpackChunkName: "CustomFieldsWidgetLazyContent" */
          '../../components/CustomFieldsWidget/CustomFieldsWidgetLazyContent'
        ).catch((err) => {
          throw new WixPatternsError({
            errorCode: 'LoadCustomFieldsWidgetLazyContentFailed',
            originalException: err,
          });
        }),
        dataExtension.initTask.status.promise?.catch((err) => {
          throw new WixPatternsError({
            errorCode: 'InitCustomFieldsDataExtensionFailed',
            originalException: err,
          });
        }),
        container.initTask.status.promise?.catch((err) => {
          throw new WixPatternsError({
            errorCode: 'InitCustomFieldsWidgetContainerFailed',
            originalException: err,
          });
        }),
        apps.initTask.status.promise?.catch(() => null),
      ]).catch((error) => {
        this.container.internalMonitor.reportError({
          error,
        });

        this.reportBi(
          cairoErrorInLoadingAComponent({
            errorType:
              error instanceof WixPatternsError ? error.name : undefined,
          }),
        );

        throw error;
      });

      this._customFieldsLazyComponents = lazyComponents;

      appLoaded?.();
    });

    return () => {
      disposers.forEach((d) => d?.());
    };
  }

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

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

  initContent() {
    const disposers = [
      addResizeObserver(
        this._widgetContentRef.current,
        this._adjustWidgetSize.bind(this),
      ),
    ];

    this._adjustWidgetSize();

    return () => {
      disposers.forEach((d) => d?.());
    };
  }

  _commonDynamicBiParams() {
    return {
      url: window.location.href,
      route: window.location.pathname,
    };
  }

  retry() {
    this.reportBi(
      cairoTryAgainClicked({
        actionName: 'Load custom fields',
        loaction: 'Custom fields widget',
      }),
    );

    this.initTask.runOnce();
  }

  get isDirty() {
    return !!this._formState?.isDirty;
  }

  get widgetSize() {
    return this._size;
  }

  get isLoading() {
    const { status } = this.initTask;
    return status.isIdle || status.isLoading;
  }

  get ActionButtonsComponent() {
    return this._customFieldsLazyComponents?.ActionButtons;
  }

  get CustomFieldsWidgetContent() {
    return this._customFieldsLazyComponents?.CustomFieldsWidgetContent;
  }

  get WixPatternsModalsContainer() {
    return this._customFieldsLazyComponents?.WixPatternsModalsContainer;
  }

  get CustomFieldModal() {
    return this._customFieldsLazyComponents?.CustomFieldModal;
  }

  get ArchiveFieldModal() {
    return this._customFieldsLazyComponents?.ArchiveFieldModal;
  }

  setWidgetContentRef(ref: HTMLDivElement | null) {
    this._widgetContentRef.current = ref;
  }

  _adjustWidgetSize() {
    if (this._widgetContentRef.current) {
      const element = this._widgetContentRef.current;

      if (element.clientWidth < 842) {
        this._size = 'small';
      } else {
        this._size = 'default';
      }
    }
  }

  get isError() {
    return this.initTask.status.isError;
  }

  async validate(): Promise<{
    isValid: boolean;
    extendedFields?: ExtendedFields;
    values?: ExtendedFields;
  }> {
    const data = this._formState?.validate();

    if (!data) {
      return {
        isValid: true,
      };
    }

    if (data?.isValid) {
      const extendedFields = data.extendedFields;
      return {
        isValid: true,
        extendedFields,
        values: extendedFields,
      };
    }

    return { isValid: false };
  }

  get hasWritePermissions() {
    return this.dataExtension.hasWritePermissions;
  }
}
