import { action, computed, makeObservable, observable } from 'mobx';
import { ConditionalModalState, TaskState } from '@wix/bex-core';
import type {
  RemoveToast,
  ShowToast,
  ToastConfig,
  Translate,
} from '@wix/bex-core';
import type { MessageModalLayoutProps } from '@wix/design-system';
import type { FieldActions } from '../types/SchemaConfig';
import type { FieldActionPermissions } from '../components/FieldActions';

export class FieldActionsState {
  handlers: FieldActions | undefined;
  permissions: FieldActionPermissions | undefined;
  readonly translate: Translate;
  readonly showToast: ShowToast | undefined;
  private _refresh: (() => Promise<void>) | undefined;

  private _currentToastRemove: RemoveToast | undefined;

  readonly confirmModal = new ConditionalModalState<
    Partial<MessageModalLayoutProps>
  >();
  readonly deleteTask = new TaskState<unknown>();
  readonly makePrimaryTask = new TaskState<unknown>();
  readonly duplicateTask = new TaskState<unknown>();
  readonly duplicateWithContentTask = new TaskState<unknown>();

  constructor(
    translate: Translate,
    handlers?: FieldActions,
    permissions?: FieldActionPermissions,
    showToast?: ShowToast,
    refresh?: () => Promise<void>,
  ) {
    this.translate = translate;
    this.handlers = handlers;
    this.permissions = permissions;
    this.showToast = showToast;
    this._refresh = refresh;
    makeObservable(this, {
      handlers: observable.ref,
      permissions: observable.ref,
      setHandlers: action,
      setPermissions: action,
      setRefresh: action,
      confirmDelete: action,
      makePrimary: action,
      duplicate: action,
      duplicateWithContent: action,
      isMakingPrimary: computed,
      isDuplicating: computed,
      isDuplicatingWithContent: computed,
    });
  }

  setHandlers(handlers: FieldActions | undefined) {
    this.handlers = handlers;
  }

  setPermissions(permissions: FieldActionPermissions | undefined) {
    this.permissions = permissions;
  }

  setRefresh(refresh: (() => Promise<void>) | undefined) {
    this._refresh = refresh;
  }

  get isMakingPrimary() {
    return this.makePrimaryTask.status.isLoading;
  }

  get isDuplicating() {
    return this.duplicateTask.status.isLoading;
  }

  get isDuplicatingWithContent() {
    return this.duplicateWithContentTask.status.isLoading;
  }

  private _showToast = (config: ToastConfig) => {
    if (!this.showToast) {
      return;
    }
    this._currentToastRemove?.();
    this._currentToastRemove = this.showToast(config).remove;
  };

  private _withRefresh = async (operation: () => Promise<unknown>) => {
    await operation();
    await this._refresh?.();
  };

  confirmDelete(fieldId: string) {
    const deleteField = this.handlers?.deleteField;
    if (!deleteField) {
      return;
    }
    const t = this.translate;
    this.confirmModal.open({
      theme: 'destructive',
      title: t('cairo.deleteModal.title'),
      content: t('cairo.deleteModal.body'),
      primaryButtonText: t('cairo.delete.button'),
      secondaryButtonText: t('cairo.cancel.button'),
      primaryButtonOnClick: () => {
        this._runDelete(fieldId, deleteField);
      },
    });
  }

  async makePrimary(fieldId: string) {
    const makePrimary = this.handlers?.makePrimary;
    if (!makePrimary || this.makePrimaryTask.status.isLoading) {
      return;
    }
    await this.makePrimaryTask.run(() =>
      this._withRefresh(() => makePrimary(fieldId)),
    );
    if (this.makePrimaryTask.status.isSuccess) {
      this._showToast({
        type: 'SUCCESS',
        message: 'Primary field updated',
        biName: 'cairo-field-action-make-primary-success',
      });
    } else if (this.makePrimaryTask.status.isError) {
      this._showToast({
        type: 'ERROR',
        message: "Couldn't update primary field",
        biName: 'cairo-field-action-make-primary-error',
        action: {
          text: 'Try again',
          onClick: () => this.makePrimary(fieldId),
          removeToastOnClick: true,
        },
      });
    }
  }

  async duplicate(fieldId: string) {
    const duplicateField = this.handlers?.duplicateField;
    if (!duplicateField || this.duplicateTask.status.isLoading) {
      return;
    }
    await this.duplicateTask.run(() =>
      this._withRefresh(() => duplicateField(fieldId)),
    );
    if (this.duplicateTask.status.isSuccess) {
      this._showToast({
        type: 'SUCCESS',
        message: 'Field duplicated',
        biName: 'cairo-field-action-duplicate-success',
      });
    } else if (this.duplicateTask.status.isError) {
      this._showToast({
        type: 'ERROR',
        message: "Couldn't duplicate field",
        biName: 'cairo-field-action-duplicate-error',
        action: {
          text: 'Try again',
          onClick: () => this.duplicate(fieldId),
          removeToastOnClick: true,
        },
      });
    }
  }

  async duplicateWithContent(fieldId: string) {
    const duplicateFieldWithContent = this.handlers?.duplicateFieldWithContent;
    if (
      !duplicateFieldWithContent ||
      this.duplicateWithContentTask.status.isLoading
    ) {
      return;
    }
    await this.duplicateWithContentTask.run(() =>
      this._withRefresh(() => duplicateFieldWithContent(fieldId)),
    );
    if (this.duplicateWithContentTask.status.isSuccess) {
      this._showToast({
        type: 'SUCCESS',
        message: 'Field duplicated with content',
        biName: 'cairo-field-action-duplicate-with-content-success',
      });
    } else if (this.duplicateWithContentTask.status.isError) {
      this._showToast({
        type: 'ERROR',
        message: "Couldn't duplicate field with content",
        biName: 'cairo-field-action-duplicate-with-content-error',
        action: {
          text: 'Try again',
          onClick: () => this.duplicateWithContent(fieldId),
          removeToastOnClick: true,
        },
      });
    }
  }

  private _runDelete = async (
    fieldId: string,
    deleteField: (id: string) => Promise<unknown>,
  ) => {
    await this.deleteTask.run(() =>
      this._withRefresh(() => deleteField(fieldId)),
    );
    if (this.deleteTask.status.isSuccess) {
      this.confirmModal.close();
      this._showToast({
        type: 'SUCCESS',
        message: 'Field deleted',
        biName: 'cairo-field-action-delete-success',
      });
    } else if (this.deleteTask.status.isError) {
      this._showToast({
        type: 'ERROR',
        message: "Couldn't delete field",
        biName: 'cairo-field-action-delete-error',
        action: {
          text: 'Try again',
          onClick: () => this._runDelete(fieldId, deleteField),
          removeToastOnClick: true,
        },
      });
    }
  };
}
