import type { Component, InjectionKey, MaybeRefOrGetter, Ref } from "vue";
import type { ServiceRequestOptions } from "./service";

type CrudRequestOptions = Pick<ServiceRequestOptions, "timeoutMs">;

/** 标准 CRUD service */
export type CrudService = {
  namespace?: string;
  page?: (
    data: Record<string, unknown>,
    options?: CrudRequestOptions,
  ) => Promise<{
    list: Record<string, unknown>[];
    pagination: { page: number; size: number; total: number };
  }>;
  list?: (
    data?: Record<string, unknown>,
    options?: CrudRequestOptions,
  ) => Promise<Record<string, unknown>[]>;
  info?: (data: { id: number | string }) => Promise<Record<string, unknown>>;
  add?: (data: Record<string, unknown>) => Promise<unknown>;
  update?: (data: Record<string, unknown>) => Promise<unknown>;
  delete?: (data: {
    ids: Array<number | string>;
    force?: boolean;
  }) => Promise<unknown>;
  restore?: (data: { ids: Array<number | string> }) => Promise<unknown>;
  /** 权限码字符串 map */
  permission?: Partial<CrudPermission> | Record<string, string>;
  /** 当前用户是否具备对应权限 */
  _permission?: Partial<CrudPermission> & Record<string, boolean>;
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  request?: (options?: any) => Promise<unknown>;
  [key: string]: unknown;
};

export type CrudPermission = {
  page: boolean;
  list: boolean;
  info: boolean;
  add: boolean;
  delete: boolean;
  update: boolean;
  /** 有则显示回收站；与 Controller `api` 含 restore 对齐 */
  restore: boolean;
};

export type CrudDict = {
  primaryId: string;
  api: {
    list: string;
    add: string;
    update: string;
    delete: string;
    info: string;
    page: string;
  };
  pagination: { page: string; size: string };
  search: { keyWord: string; query: string };
  sort: { order: string; prop: string };
  label: Record<string, string>;
};

export type CrudFormComponent = {
  name?: string | Component;
  /** 含 dict.get('x') 等 ComputedRef */
  props?: unknown;
};

export type CrudSearchItem = {
  prop: string;
  /** 筛选项不展示 label；占位用 `placeholder` 或 `phMode` / `fieldKey` */
  label?: string;
  type?: "input" | "select" | "date" | "daterange" | "number-range";
  placeholder?: string;
  options?: MaybeRefOrGetter<
    Array<{ label: string; value: string | number | boolean }>
  >;
  /** 业务字典 type.key；有则拉 options */
  dict?: string;
  /** 下拉多选 */
  multiple?: boolean;
  /** 区间：提交时拆成 min/max 请求参数 */
  range?: {
    min: string;
    max: string;
    rangeType:
      | "int"
      | "float"
      | "year"
      | "month"
      | "day"
      | "datetime";
  };
  /** component.name 走 registry */
  component?: CrudFormComponent;
  /**初始化值（写入 search form；重置亦回到此值）*/
  value?: unknown;
  /** i18n：field.{table}.{prop}，运行时解析占位符 */
  fieldKey?: string;
  /** 无翻译时的字段中文名（EPS comment） */
  nameFallback?: string;
  /** 占位符模式：搜索 / 选择 / 关键字 / 区间 */
  phMode?: "search" | "select" | "keyword" | "range";
  /** keyword 多字段 fieldKey 列表 */
  keywordParts?: string[];
};

export type CrudOpButton =
  | "edit"
  | "delete"
  | "info"
  | {
      label: string;
      hidden?: boolean;
      disabled?: boolean;
      variant?:
        | "softPrimary"
        | "softDestructive"
        | "softSuccess"
        | "ghost"
        | "outline";
      onClick: (row: Record<string, unknown>) => void;
    };

export type CrudColumn = {
  prop?: string;
  label?: string;
  /** i18n 完整 key，优先于 field.*（如 i18n.langName） */
  labelKey?: string;
  /** 显式 field.{table}.{prop}；缺省时按 EPS 推断 */
  fieldKey?: string;
  /** selection | index | op | expand */
  type?: "selection" | "index" | "op" | "expand";
  width?: string | number;
  minWidth?: string | number;
  align?: "left" | "center" | "right";
  /** 横向滚动时固定列；`type: 'op'` 未写时默认 `right` */
  fixed?: "left" | "right";
  hidden?: boolean;
  /** true / custom 可点排序；asc|desc 表示默认方向 */
  sortable?: boolean | "custom" | "asc" | "desc" | "ascending" | "descending";
  /** 长文本省略 + tooltip（vm-table 支持） */
  showOverflowTooltip?: boolean;
  slot?: string;
  formatter?: (row: Record<string, unknown>, value: unknown) => string;
  /** op 列：edit/delete/info 或自定义按钮对象 */
  buttons?: CrudOpButton[] | ((row: Record<string, unknown>) => CrudOpButton[]);
  /** 单元格组件：name 为注册名或直接组件 */
  component?: {
    name?: string | Component;
    /** 含 dict.get('status') 等 ComputedRef */
    props?: unknown;
  };
  /** dict.get / dict.options（支持 ComputedRef） */
  dict?: MaybeRefOrGetter<
    Array<{
      label: string;
      value: string | number | boolean;
      type?: string;
      color?: string;
    }>
  >;
  children?: CrudColumn[];
};

export type CrudFormItem = {
  prop: string;
  label: string;
  type?: "input" | "textarea" | "select" | "switch" | "radio" | "number";
  required?: boolean | ((form: Record<string, unknown>) => boolean);
  placeholder?: string;
  /** 控件禁用 */
  disabled?: boolean;
  /** select 多选 */
  multiple?: boolean;
  /** 扁平或树；options: dict.get('x') */
  options?: MaybeRefOrGetter<
    Array<{
      label: string;
      value: string | number | boolean;
      children?: Array<{
        label: string;
        value: string | number | boolean;
        children?: unknown[];
      }>;
    }>
  >;
  /** 业务字典 type.key；有则拉 options（与 search 一致） */
  dict?: string;
  /** 按桌面 24 栅格配置（全宽 24）；移动端自动映射到 12 列 */
  span?: number;
  hidden?: boolean | ((form: Record<string, unknown>) => boolean);
  /** 用 component 描述控件 */
  component?: CrudFormComponent;
  /**
   * 新增表单初始化值（rowAdd / openUpsert add 时写入；`:add-data` 同名字段优先）。
   * 可为函数：打开弹窗时再求值（如字典第一项 key）。勿写在 component.props。
   */
  value?: unknown;
  rules?: unknown;
};

export type CrudTrashMode =
  | "default"
  | "onlyTrashed"
  | "withTrashed"
  /** 业务 dataI18n：展示某语种 pack 展开条目 */
  | "dataI18n";

export type CrudRefreshHelpers = {
  next: (params: Record<string, unknown>) => Promise<unknown>;
  done: () => void;
  render: (
    list:
      | Record<string, unknown>[]
      | { list: Record<string, unknown>[]; pagination?: unknown },
    pagination?: { page?: number; size?: number; total?: number },
  ) => void;
};

export type CrudDeleteHelpers = {
  next: (params?: Record<string, unknown>) => Promise<unknown>;
};

export type CrudOptions = {
  /** EPS service 对象，如 service.base.user */
  service: CrudService;
  dict?: Partial<CrudDict>;
  permission?: Partial<CrudPermission>;
  onRefresh?: (
    params: Record<string, unknown>,
    helpers: CrudRefreshHelpers,
  ) => void | Promise<void>;
  onDelete?: (
    selection: Record<string, unknown>[],
    helpers: CrudDeleteHelpers,
  ) => void | Promise<void>;
};

export type CrudUpsertOptions = {
  items?: CrudFormItem[];
  /** EPS 自动生成时排除的字段（不展示、不校验） */
  ignoreFields?: string[];
  /** false：关闭 Form.setAuto，仅用手动 items */
  auto?: boolean;
  props?: Record<string, unknown>;
  dialog?: {
    title?: string;
    /** 显式 false 强制隐藏确定；未设时仍按 info 模式自动隐藏 */
    confirm?: boolean;
    /** 显式 false 隐藏关闭；默认 true */
    close?: boolean;
    /** 弹窗高度，如 800 / '800px'；最高 800px */
    height?: string | number;
    confirmText?: string;
    closeText?: string;
  };
  sync?: boolean;
  onOpen?: (data: Record<string, unknown>) => void;
  onOpened?: (data: Record<string, unknown>) => void;
  onClose?: (action: "close" | "submit", done: () => void) => void;
  onInfo?: (
    data: Record<string, unknown>,
    helpers: {
      next: (
        data?: Record<string, unknown>,
      ) => Promise<Record<string, unknown>>;
      done: (data: Record<string, unknown>) => void;
      close: () => void;
    },
  ) => void | Promise<void>;
  onSubmit?: (
    data: Record<string, unknown>,
    helpers: {
      next: (data?: Record<string, unknown>) => Promise<unknown>;
      done: () => void;
      close: () => void;
    },
  ) => void | Promise<void | unknown>;
};

/** useImport → vm-import-btn（不经 toolbar props） */
export type CrudImportOptions = {
  /**
   * 导入提交拦截。须自行 `next()` 才会上传；
   * - `next()` / `next(file)` → multipart 文件
   * - `next(rows)` → JSON `{ rows }`（改写后直传）
   */
  onSubmit?: (
    payload: {
      file: File;
      rows: Record<string, unknown>[];
      headers: string[];
    },
    helpers: {
      next: (
        payload?: File | Record<string, unknown>[],
      ) => Promise<{
        inserted: number;
        updated: number;
        failed: Array<{ row: number; message: string }>;
      }>;
      done: () => void;
      close: () => void;
    },
  ) => void | Promise<void | unknown>;
};

export type CrudTableOptions = {
  columns?: CrudColumn[];
  /** EPS 自动生成时排除的字段 */
  ignoreFields?: string[];
  /** false：关闭 Table.setAuto，仅用手动 columns */
  auto?: boolean;
  autoHeight?: boolean;
  border?: boolean;
  contextMenu?: boolean | string[];
  rowKey?: string;
  /** 树表：list 含 children 时缩进展开 */
  tree?: boolean;
  treeLazy?: boolean;
  /** 树表默认全部展开（为 true 时忽略 defaultExpandLevel） */
  defaultExpandAll?: boolean;
  /** 树表默认展开到第几级（1=仅根、不展开；默认 1） */
  defaultExpandLevel?: number;
  /** 默认排序；请求键由 dict.sort 决定 */
  defaultSort?: {
    prop: string;
    order: "asc" | "desc" | "ascending" | "descending";
  };
  /** 排序变化时是否 refresh，默认 true */
  sortRefresh?: boolean;
  plugins?: unknown[];
};

export type CrudSearchOptions = {
  items?: CrudSearchItem[];
};

export type CrudContext = {
  service: CrudService;
  loading: Ref<boolean>;
  list: Ref<Record<string, unknown>[]>;
  selection: Ref<Record<string, unknown>[]>;
  pagination: Ref<{ page: number; size: number; total: number }>;
  params: Ref<Record<string, unknown>>;
  trashMode: Ref<CrudTrashMode>;
  /** 语言 Tab 当前查看的语种（与 i18n.lang 启用列表同源） */
  dataI18nLangCode: Ref<string>;
  /** 语言 Tab 字段列元数据（最近一次 entries） */
  dataI18nFields: Ref<Array<{ name: string; label: string }>>;
  permission: Ref<CrudPermission>;
  dict: CrudDict;
  refresh: (extra?: Record<string, unknown>) => Promise<unknown>;
  setParams: (p: Record<string, unknown>, doRefresh?: boolean) => void;
  /** doRefresh=false 时只清 params 不拉列表（供 search 重置后带初始值再 search） */
  resetParams: (doRefresh?: boolean) => void;
  setSelection: (rows: Record<string, unknown>[]) => void;
  getPermission: (key?: keyof CrudPermission) => boolean | CrudPermission;
  getParams: () => Record<string, unknown>;
  /** 与 refresh 同源查询体（筛选 / 排序 / 回收站 + 分页） */
  buildListQuery: (extra?: Record<string, unknown>) => Record<string, unknown>;
  /** 导出专用：筛选 / 排序 / 列表或回收站视图，不含 page、size */
  buildExportQuery: (extra?: Record<string, unknown>) => Record<string, unknown>;
  /** 与 refresh 同源 POST page（含 onRefresh 注入条件） */
  requestPage: (
    body: Record<string, unknown>,
    options?: { timeoutMs?: number },
  ) => Promise<{
    list: Record<string, unknown>[];
    pagination?: { page?: number; size?: number; total?: number };
  }>;
  rowAdd: (defaults?: Record<string, unknown>) => void;
  rowAppend: (data?: Record<string, unknown>) => void;
  rowEdit: (row: Record<string, unknown>) => Promise<void>;
  rowInfo: (row: Record<string, unknown>) => Promise<void>;
  rowClose: () => void;
  /** 打开 upsert，不校验 add 权限 */
  openUpsert: (
    form?: Record<string, unknown>,
    mode?: "add" | "update" | "info",
  ) => void;
  rowDelete: (
    rows?: Record<string, unknown>[],
    force?: boolean,
  ) => Promise<void>;
  rowRestore: (rows?: Record<string, unknown>[]) => Promise<void>;
  upsertVisible: Ref<boolean>;
  upsertMode: Ref<"add" | "update" | "info">;
  upsertForm: Ref<Record<string, unknown>>;
  upsertSubmit: () => Promise<void>;
  upsertClose: () => void;
  patchUpsertForm: (patch: Record<string, unknown>) => void;
  getUpsertForm: () => Record<string, unknown>;
  /** vm-search 注册；vm-toolbar 搜索/重置读取 */
  searchActions: import("vue").ShallowRef<{
    search: () => void;
    reset: () => void;
  } | null>;
  /** vm-search 是否有筛选项；无配置时不显示 toolbar 搜索/重置 */
  hasSearchFilters: Ref<boolean>;
};

/** 表格右键菜单项 */
export type CtxMenuItem = {
  key: string;
  label: string;
  disabled?: boolean;
};

/** 树形下拉选项 */
export type TreeSelectOption = {
  label?: string;
  value?: string | number | boolean;
  children?: TreeSelectOption[];
  [key: string]: unknown;
};

/** CRUD Table 插件标记 */
export type TablePlugin = {
  __plugin: string;
  [key: string]: unknown;
};

export type { InjectionKey, Ref };
