import type { ContextMenuItem } from '#/components/context-menu';
import { menuDivider, showContextMenu } from '#/components/context-menu';

import { message } from 'ant-design-vue';
import type {
  CellEditContext,
  HeaderContextMenuContext,
  SpreadsheetColumnConfig,
  SpreadsheetEngineExpose,
  SpreadsheetHeaderConfig,
  SpreadsheetTableConfig,
} from '../types';

export interface HeaderLayoutActions {
  toggleFixed: (col: number) => void;
  setHeaderColor: (col: number, color?: string) => void;
  isFixed: (col: number) => boolean;
  getHeaderColor: (col: number) => string | undefined;
}

export interface SpreadsheetAdminMenuActions {
  onOpenConfig: () => void;
  onAddColumn: () => void;
  onSetColumn: (col: number) => void;
}

export interface SpreadsheetMenuActions {
  col: number;
  layoutActions?: HeaderLayoutActions;
  onOpenHeaderColorPicker: (col: number) => void;
  admin?: SpreadsheetAdminMenuActions;
}

function resolveCustomItems<T>(
  config:
    | ContextMenuItem[]
    | ((ctx: T) => ContextMenuItem[])
    | undefined,
  ctx: T,
): ContextMenuItem[] {
  if (!config) return [];
  return typeof config === 'function' ? config(ctx) : config;
}

function buildCellBuiltinItems(
  ctx: CellEditContext,
  engine: SpreadsheetEngineExpose,
  onStartEdit: (row: number, col: number) => void,
): ContextMenuItem[] {
  const canEditCell = engine.canEdit(ctx.rowIndex, ctx.colIndex);
  const sel = ctx.selection;
  return [
    {
      key: 'edit',
      label: '编辑',
      iconName: 'ant-design:edit-outlined',
      disabled: !canEditCell,
      handler: () => onStartEdit(ctx.rowIndex, ctx.colIndex),
    },
    {
      key: 'copy',
      label: '复制',
      iconName: 'ant-design:copy-outlined',
      disabled: !sel,
      handler: () => {
        if (sel) {
          engine.copy();
          message.success('复制成功');
        }
      },
    },
    {
      key: 'copy-image',
      label: '复制为图片',
      iconName: 'ant-design:picture-outlined',
      disabled: !sel,
      handler: () => {
        if (!sel) return;
        void engine
          .copyAsImage()
          .then(() => {
            message.success('已复制为图片');
          })
          .catch(() => {
            message.warning('复制图片失败，请检查浏览器剪贴板权限');
          });
      },
    },
    {
      key: 'paste',
      label: '粘贴',
      iconName: 'ant-design:snippets-outlined',
      disabled: !engine.canPaste(),
      handler: () => {
        void engine.paste();
      },
    },
    {
      key: 'undo',
      label: '撤回',
      iconName: 'ant-design:undo-outlined',
      disabled: !engine.canUndo(),
      handler: () => {
        void engine.undo();
      },
    },
  ];
}

function buildFixedItem(
  col: number,
  layoutActions?: HeaderLayoutActions,
): ContextMenuItem | null {
  if (!layoutActions) return null;
  const fixed = layoutActions.isFixed(col);
  return {
    key: 'toggle-fixed',
    label: fixed ? '取消固定' : '固定此列',
    iconName: 'ant-design:pushpin-outlined',
    handler: () => layoutActions.toggleFixed(col),
  };
}

function buildHeaderColorItem(
  col: number,
  onOpen: (col: number) => void,
): ContextMenuItem {
  return {
    key: 'header-color',
    label: '表头颜色',
    iconName: 'ant-design:bg-colors-outlined',
    handler: () => onOpen(col),
  };
}

function buildAdminFlatItemsForCol(
  col: number,
  admin: SpreadsheetAdminMenuActions,
): ContextMenuItem[] {
  return [
    {
      key: 'admin-config',
      label: 'Excel 配置',
      iconName: 'mdi:table-cog',
      handler: () => admin.onOpenConfig(),
    },
    {
      key: 'admin-add-col',
      label: '新增一列',
      iconName: 'ant-design:plus-outlined',
      handler: () => admin.onAddColumn(),
    },
    {
      key: 'admin-set-col',
      label: '设置列',
      iconName: 'ant-design:setting-outlined',
      handler: () => admin.onSetColumn(col),
    },
  ];
}

function buildColumnSubmenu(menuActions: SpreadsheetMenuActions): ContextMenuItem {
  const { col, layoutActions, onOpenHeaderColorPicker, admin } = menuActions;
  const children: ContextMenuItem[] = [];

  if (admin) {
    children.push({
      key: 'admin-add-col',
      label: '新增一列',
      iconName: 'ant-design:plus-outlined',
      handler: () => admin.onAddColumn(),
    });
    children.push({
      key: 'admin-set-col',
      label: '设置列',
      iconName: 'ant-design:setting-outlined',
      handler: () => admin.onSetColumn(col),
    });
  }

  const fixedItem = buildFixedItem(col, layoutActions);
  if (fixedItem) children.push(fixedItem);

  children.push(buildHeaderColorItem(col, onOpenHeaderColorPicker));

  return {
    key: 'column-submenu',
    label: '列',
    iconName: 'ant-design:table-outlined',
    children,
  };
}

function buildHeaderMenuItems(menuActions: SpreadsheetMenuActions): ContextMenuItem[] {
  const { col, layoutActions, onOpenHeaderColorPicker, admin } = menuActions;
  const items: ContextMenuItem[] = [];

  const fixedItem = buildFixedItem(col, layoutActions);
  if (fixedItem) items.push(fixedItem);

  items.push(buildHeaderColorItem(col, onOpenHeaderColorPicker));

  if (admin) {
    items.push(...buildAdminFlatItemsForCol(col, admin));
  }

  return items;
}

function buildCellAdminItems(menuActions: SpreadsheetMenuActions): ContextMenuItem[] {
  if (!menuActions.admin) return [];
  return [
    {
      key: 'admin-config',
      label: 'Excel 配置',
      iconName: 'mdi:table-cog',
      handler: () => menuActions.admin!.onOpenConfig(),
    },
    buildColumnSubmenu(menuActions),
  ];
}

function mergeMenus(
  builtin: ContextMenuItem[],
  custom: ContextMenuItem[],
): ContextMenuItem[] {
  if (!custom.length) return builtin;
  return [...builtin, menuDivider('__divider__'), ...custom];
}

function appendAdminBlock(
  items: ContextMenuItem[],
  adminItems: ContextMenuItem[],
): ContextMenuItem[] {
  if (!adminItems.length) return items;
  return [...items, menuDivider('__admin_divider__'), ...adminItems];
}

export function openCellContextMenu(
  e: MouseEvent,
  ctx: CellEditContext,
  column: SpreadsheetColumnConfig | undefined,
  engine: SpreadsheetEngineExpose,
  onStartEdit: (row: number, col: number) => void,
  menuActions?: SpreadsheetMenuActions,
) {
  const builtin = buildCellBuiltinItems(ctx, engine, onStartEdit);
  const custom = resolveCustomItems(column?.contextMenu, ctx);
  const adminItems = menuActions ? buildCellAdminItems(menuActions) : [];
  showContextMenu(
    e,
    appendAdminBlock(mergeMenus(builtin, custom), adminItems),
    ctx,
  );
}

export function openHeaderContextMenu(
  e: MouseEvent,
  ctx: HeaderContextMenuContext,
  header: SpreadsheetHeaderConfig | undefined,
  tableConfig: SpreadsheetTableConfig,
  menuActions: SpreadsheetMenuActions,
) {
  const builtin = buildHeaderMenuItems(menuActions);
  let custom = resolveCustomItems(header?.contextMenu, ctx);
  if (!custom.length) {
    custom = resolveCustomItems(tableConfig.headerContextMenu, ctx);
  }
  showContextMenu(e, mergeMenus(builtin, custom), ctx);
}
