import { action, computed, makeObservable, observable, toJS } from 'mobx';
import { MenuDataType } from '@music163/tango-helpers';
import { AbstractWorkspace } from './abstract-workspace';

export type SimulatorNameType = 'desktop' | 'phone';

export type DesignerViewType = 'design' | 'code' | 'dual';

interface ISimulatorType {
  name: SimulatorNameType;
  width: number;
  height: number;
}

interface IViewportBounding {
  width: number;
  height: number;
}

interface IDesignerOptions {
  workspace: AbstractWorkspace;
  simulator?: SimulatorNameType | ISimulatorType;
  /**
   * 菜单配置
   */
  menuData: MenuDataType;
  activeSidebarPanel?: string;
  /**
   * 默认激活的视图模式
   */
  activeView?: DesignerViewType;
}

const ISimulatorTypes: Record<string, ISimulatorType> = {
  desktop: {
    name: 'desktop',
    width: 1366,
    height: 800,
  },
  phone: {
    name: 'phone',
    width: 375,
    height: 812,
  },
};

export class Designer {
  /**
   * 当前的沙箱模拟器类型
   */
  _simulator: ISimulatorType = ISimulatorTypes.desktop;

  /**
   * 当前的视图尺寸
   */
  _viewport: IViewportBounding = {
    width: 1366,
    height: 800,
  };

  /**
   * 当前激活的视图
   */
  _activeView: DesignerViewType = 'design';

  /**
   * 当前选中的侧边栏面板
   */
  _activeSidebarPanel = '';

  /**
   * 是否显示智能引导
   */
  _showSmartWizard = false;

  /**
   * 是否显示添加组件面板
   */
  _showAddComponentPopover = false;

  /**
   * 添加组件面板的位置
   */
  _addComponentPopoverPosition = { clientX: 0, clientY: 0 };

  /**
   * 是否显示右键菜单
   */
  _showContextMenu = false;

  /**
   * 右键菜单在 iframe 上的位置
   */
  _contextMenuPosition = { clientX: 0, clientY: 0 };

  /**
   * 是否显示右侧面板
   */
  _showRightPanel = true;

  /**
   * 是否预览模式
   */
  _isPreview = false;

  /**
   * 菜单列表
   */
  _menuData?: MenuDataType = null;

  private readonly workspace: AbstractWorkspace;

  get simulator(): ISimulatorType {
    return toJS(this._simulator);
  }

  get viewport() {
    return toJS(this._viewport);
  }

  get activeView() {
    return this._activeView;
  }

  get isPreview() {
    return this._isPreview;
  }

  get showSmartWizard() {
    return this._showSmartWizard;
  }

  get activeSidebarPanel() {
    return this._activeSidebarPanel;
  }

  get showRightPanel() {
    return this._showRightPanel;
  }

  get showAddComponentPopover() {
    return this._showAddComponentPopover;
  }

  get addComponentPopoverPosition() {
    return this._addComponentPopoverPosition;
  }

  get showContextMenu() {
    return this._showContextMenu;
  }

  get contextMenuPosition() {
    return this._contextMenuPosition;
  }

  get menuData() {
    return this._menuData ?? ([] as MenuDataType);
  }

  constructor(options: IDesignerOptions) {
    this.workspace = options.workspace;

    const {
      simulator,
      menuData,
      activeSidebarPanel: defaultActiveSidebarPanel,
      activeView: defaultActiveView,
    } = options;

    if (menuData) {
      this.setMenuData(menuData);
    }

    // 默认设计器模式
    if (simulator) {
      this.setSimulator(simulator);
    }

    // 默认展开的侧边栏
    if (defaultActiveSidebarPanel) {
      this.setActiveSidebarPanel(defaultActiveSidebarPanel);
    }

    // 默认激活的视图
    if (defaultActiveView) {
      this.setActiveView(defaultActiveView);
    }

    makeObservable(this, {
      _simulator: observable,
      _viewport: observable,
      _activeView: observable,
      _activeSidebarPanel: observable,
      _showSmartWizard: observable,
      _showRightPanel: observable,
      _showAddComponentPopover: observable,
      _addComponentPopoverPosition: observable,
      _showContextMenu: observable,
      _contextMenuPosition: observable,
      _menuData: observable,
      _isPreview: observable,
      simulator: computed,
      viewport: computed,
      activeView: computed,
      activeSidebarPanel: computed,
      isPreview: computed,
      showRightPanel: computed,
      showSmartWizard: computed,
      showAddComponentPopover: computed,
      addComponentPopoverPosition: computed,
      showContextMenu: computed,
      contextMenuPosition: computed,
      menuData: computed,
      setSimulator: action,
      setViewport: action,
      setActiveView: action,
      setActiveSidebarPanel: action,
      closeSidebarPanel: action,
      toggleRightPanel: action,
      toggleSmartWizard: action,
      toggleIsPreview: action,
      toggleAddComponentPopover: action,
      toggleContextMenu: action,
    });
  }

  setSimulator(value: ISimulatorType | SimulatorNameType) {
    if (typeof value === 'string') {
      this._simulator = ISimulatorTypes[value];
    } else {
      this._simulator = value;
    }
  }

  setViewport(value: IViewportBounding) {
    this._viewport = value;
  }

  setActiveView(view: DesignerViewType) {
    this._activeView = view;
    if (view === 'dual') {
      this.setActiveSidebarPanel('');
      this.toggleRightPanel(false);
      this.toggleIsPreview(true);
    } else if (view === 'design') {
      this.toggleIsPreview(false);
    }
  }

  setActiveSidebarPanel(panel: string) {
    if (panel && panel !== this.activeSidebarPanel) {
      this._activeSidebarPanel = panel;
    } else {
      this._activeSidebarPanel = '';
    }
  }

  setMenuData(menuData: MenuDataType) {
    this._menuData = menuData;
  }

  closeSidebarPanel() {
    this._activeSidebarPanel = '';
  }

  toggleSmartWizard(value: boolean) {
    this._showSmartWizard = value;
  }

  toggleRightPanel(value?: boolean) {
    this._showRightPanel = value ?? !this._showRightPanel;
  }

  /**
   * 显示添加组件面板
   * @param value 是否显示
   * @param position 坐标
   */
  toggleAddComponentPopover(
    value: boolean,
    position: {
      clientX: number;
      clientY: number;
    } = this.addComponentPopoverPosition,
  ) {
    this._showAddComponentPopover = value;
    this._addComponentPopoverPosition = position;
  }

  toggleIsPreview(value: boolean) {
    this._isPreview = value ?? !this._isPreview;
    if (value) {
      this.workspace.selectSource.clear();
    }
  }

  toggleContextMenu(
    value: boolean,
    position: {
      clientX: number;
      clientY: number;
    } = this.contextMenuPosition,
  ) {
    this._showContextMenu = value;
    this._contextMenuPosition = position;
  }
}
