import { Schema } from "effect";
import { Expression, HttpRequestResult } from "../../share/expression.js";
import { Locale } from "../../share/locale.js";
import { md } from "../../share/markdown.js";
import { ActionSchemaFields } from "../actions/schema.js";
import { FormConfig } from "../form/schema.js";
import { allColumnSchemas } from "./utils/resolve.js";
import { CelRowAccess, registerRowVariablesIfAbsent } from "./utils/shared.js";
export { getStructFieldTitle, getStructFieldDescription } from "./utils/schema-meta.js";
const KIND = "shwfed.component.table";
export const metadata = {
  name: "\u8868\u683C",
  icon: "fluent:table-20-regular",
  // Atomic operations — compose them on one button (ordered triggers) to get
  // the legacy combined behaviours. Only `search` actually fetches data;
  // `reset-query` / `reset-pagination` / `clear-selection` just prepare state.
  // The `*-row` / `*-selected` trio edits the row list locally — no server
  // round-trip — for tables wired up as an editable surface.
  operations: [
    { id: "reset-query", name: "\u91CD\u7F6E\u641C\u7D22\u6761\u4EF6", icon: "fluent:arrow-reset-20-regular" },
    { id: "reset-pagination", name: "\u91CD\u7F6E\u5206\u9875\u5E76\u6267\u884C\u641C\u7D22", icon: "fluent:arrow-previous-20-regular" },
    { id: "search", name: "\u6267\u884C\u641C\u7D22", icon: "fluent:search-20-regular" },
    { id: "clear-selection", name: "\u6E05\u7A7A\u6240\u6709\u9009\u4E2D\u884C", icon: "fluent:select-all-off-20-regular" },
    { id: "add-row", name: "\u65B0\u589E\u4E00\u884C", icon: "fluent:add-20-regular" },
    { id: "duplicate-selected", name: "\u590D\u5236\u9009\u4E2D\u884C", icon: "fluent:copy-20-regular" },
    { id: "delete-selected", name: "\u5220\u9664\u9009\u4E2D\u884C", icon: "fluent:delete-20-regular" }
  ]
};
const SortItem = Schema.Struct({
  id: Schema.String.annotations({ description: "\u5217 ID" }),
  desc: Schema.optionalWith(Schema.Boolean, { default: () => false }).annotations({
    description: "\u662F\u5426\u964D\u5E8F"
  })
}).annotations({ title: "SortItem", description: "\u6392\u5E8F\u89C4\u5219" });
const ColumnPinning = Schema.Struct({
  left: Schema.optional(Schema.Array(Schema.String)).annotations({
    description: "\u56FA\u5B9A\u5728\u5DE6\u4FA7\u7684\u5217 ID \u5217\u8868"
  }),
  right: Schema.optional(Schema.Array(Schema.String)).annotations({
    description: "\u56FA\u5B9A\u5728\u53F3\u4FA7\u7684\u5217 ID \u5217\u8868"
  })
}).annotations({ title: "ColumnPinning", description: "\u5217\u56FA\u5B9A\u914D\u7F6E" });
const RowPinning = Schema.Struct({
  top: Schema.optional(Schema.Array(Schema.String)).annotations({
    description: "\u56FA\u5B9A\u5728\u9876\u90E8\u7684\u884C ID \u5217\u8868"
  }),
  bottom: Schema.optional(Schema.Array(Schema.String)).annotations({
    description: "\u56FA\u5B9A\u5728\u5E95\u90E8\u7684\u884C ID \u5217\u8868"
  })
}).annotations({ title: "RowPinning", description: "\u884C\u56FA\u5B9A\u914D\u7F6E" });
const InitialState = Schema.Struct({
  columnVisibility: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Boolean })).annotations({
    description: "\u5217\u53EF\u89C1\u6027\u6620\u5C04\uFF0C\u952E\u4E3A\u5217 ID\uFF0C\u503C\u4E3A\u662F\u5426\u53EF\u89C1"
  }),
  columnOrder: Schema.optional(Schema.Array(Schema.String)).annotations({
    description: "\u5217\u987A\u5E8F\uFF0C\u5217 ID \u6570\u7EC4"
  }),
  columnPinning: Schema.optional(ColumnPinning),
  rowPinning: Schema.optional(RowPinning),
  sorting: Schema.optional(Schema.Array(SortItem)).annotations({
    description: "\u521D\u59CB\u6392\u5E8F\u72B6\u6001"
  }),
  expanded: Schema.optional(Schema.Union(
    Schema.Boolean,
    Schema.Record({ key: Schema.String, value: Schema.Boolean })
  )).annotations({
    description: "\u521D\u59CB\u5C55\u5F00\u72B6\u6001\uFF0Ctrue \u8868\u793A\u5168\u90E8\u5C55\u5F00\uFF0C\u6216\u6309\u884C ID \u6620\u5C04"
  }),
  grouping: Schema.optional(Schema.Array(Schema.String)).annotations({
    description: "\u5206\u7EC4\u5217 ID \u5217\u8868"
  }),
  columnSizing: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Number })).annotations({
    description: "\u5217\u5BBD\u6620\u5C04\uFF0C\u952E\u4E3A\u5217 ID\uFF0C\u503C\u4E3A\u50CF\u7D20\u5BBD\u5EA6"
  }),
  rowSelection: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Boolean })).annotations({
    description: "\u521D\u59CB\u884C\u9009\u4E2D\u72B6\u6001\u6620\u5C04"
  })
}).annotations({
  title: "InitialState",
  description: "\u8868\u683C\u521D\u59CB\u72B6\u6001"
});
export const Pagination = Schema.Struct({
  // `pageSize` is required so the editor cannot save "pagination on but no
  // page size" — the toggle in config.vue owns the on/off axis, and turning
  // it on initializes `pageSize` explicitly. No `optionalWith(default)`
  // anywhere in this struct: defaults would re-materialize on every decode
  // pass (see use-editor confirm) and undo the user's intent of leaving a
  // field unset.
  pageSize: Schema.Number.pipe(Schema.int(), Schema.positive()).annotations({
    title: "\u521D\u59CB\u6BCF\u9875\u884C\u6570",
    description: "\u521D\u59CB\u6BCF\u9875\u884C\u6570"
  }),
  pageSizes: Schema.optional(
    Schema.Array(Schema.Number.pipe(Schema.int(), Schema.positive()))
  ).annotations({
    title: "\u53EF\u9009\u5206\u9875\u5927\u5C0F",
    description: "\u53EF\u9009\u5206\u9875\u5927\u5C0F\u5217\u8868\uFF1B\u7559\u7A7A\u5219\u4E0D\u663E\u793A\u9875\u5927\u5C0F\u9009\u62E9\u5668"
  }),
  pageIndex: Schema.optional(
    Schema.Number.pipe(Schema.int(), Schema.nonNegative())
  ).annotations({
    description: "\u521D\u59CB\u9875\u7801\uFF08\u4ECE 0 \u5F00\u59CB\uFF09\uFF1B\u7559\u7A7A\u89C6\u4E3A 0"
  }),
  left: Schema.optional(Locale).annotations({
    title: "\u5206\u9875\u680F\u5DE6\u4FA7",
    description: "\u5206\u9875\u680F\u5DE6\u4FA7\u672C\u5730\u5316 Markdown \u5185\u5BB9"
  }),
  right: Schema.optional(Locale).annotations({
    title: "\u5206\u9875\u680F\u53F3\u4FA7",
    description: "\u5206\u9875\u680F\u53F3\u4FA7\u672C\u5730\u5316 Markdown \u5185\u5BB9"
  })
}).annotations({
  title: "Pagination",
  description: "\u5206\u9875\u914D\u7F6E"
});
export const ColumnGroup = Schema.Struct({
  id: Schema.UUID.annotations({ description: "\u5217\u5206\u7EC4\u552F\u4E00\u6807\u8BC6" }),
  title: Schema.optional(Locale).annotations({
    title: "\u5206\u7EC4\u6807\u9898",
    description: "\u5217\u5206\u7EC4\u6807\u9898\u7684\u672C\u5730\u5316\u6587\u672C"
  }),
  tooltip: Schema.optional(Locale).annotations({
    title: "\u5206\u7EC4\u63D0\u793A",
    description: "\u5217\u5206\u7EC4\u63D0\u793A\u7684\u672C\u5730\u5316\u6587\u672C"
  })
}).annotations({
  title: "ColumnGroup",
  description: "\u5217\u5206\u7EC4\u5B9A\u4E49"
});
const QUERY_VAR_DESCRIPTION = "\u641C\u7D22\u6761\u4EF6\u5F53\u524D\u72B6\u6001\uFF1B\u672A\u914D\u7F6E\u641C\u7D22\u6761\u4EF6\u65F6\u4E3A\u7A7A\u5BF9\u8C61";
const JSON_VAR_DESCRIPTION = "\u5DF2\u89E3\u6790\u7684 JSON \u54CD\u5E94\uFF1B\u672A\u914D\u7F6E `request` \u65F6\u4E3A `none`";
const SORTS_VAR_DESCRIPTION = md`
  当前的排序状态，为一个**列表**，每个元素包含两个字段：

  - \`key: string\` 为该列上配置的键
  - \`mode: 'asc' | 'desc'\` 为该列的排序状态

  未排序的字段，**不会出现在这个列表中**。
`;
export function configureTableActionsScope(env, configure) {
  configure(env);
  env.registerVariable("selected", "list<dyn>", {
    label: "\u5DF2\u9009\u884C",
    description: "\u5F53\u524D\u5DF2\u52FE\u9009\u7684\u6240\u6709\u884C\uFF08`row` \u7684\u6570\u7EC4\uFF09"
  });
  env.registerVariable("query", "dyn", {
    label: "\u641C\u7D22\u6761\u4EF6",
    description: QUERY_VAR_DESCRIPTION
  });
  env.registerVariable("sorts", "list<map<string, string>>", {
    label: "\u6392\u5E8F\u72B6\u6001",
    description: SORTS_VAR_DESCRIPTION
  });
}
export function registerDataSourceRequestVars(env) {
  env.registerVariable("pageIndex", "number", {
    label: "\u5F53\u524D\u9875\u7801",
    description: "\u4ECE `0` \u5F00\u59CB\uFF1B\u672A\u542F\u7528\u5206\u9875\u65F6\u4E3A `0`"
  });
  env.registerVariable("pageSize", "number", {
    label: "\u6BCF\u9875\u884C\u6570",
    description: "\u5F53\u524D\u6BCF\u9875\u884C\u6570\uFF1B\u672A\u542F\u7528\u5206\u9875\u65F6\u4E3A `0`"
  });
  env.registerVariable("sorts", "list<map<string, string>>", {
    label: "\u6392\u5E8F\u72B6\u6001",
    description: SORTS_VAR_DESCRIPTION
  });
  env.registerVariable("query", "dyn", {
    label: "\u641C\u7D22\u6761\u4EF6",
    description: QUERY_VAR_DESCRIPTION
  });
}
export function registerDataSourceResponseVars(env) {
  env.registerVariable("json", "optional<dyn>", {
    label: "HTTP \u54CD\u5E94\u4F53",
    description: JSON_VAR_DESCRIPTION
  });
  env.registerVariable("query", "dyn", {
    label: "\u641C\u7D22\u6761\u4EF6",
    description: QUERY_VAR_DESCRIPTION
  });
}
export function DataSource(configure, extras) {
  const CelRequest = Expression({
    configure: (env) => {
      configure(env);
      extras?.request?.(env);
    },
    resultType: HttpRequestResult
  });
  const CelRows = Expression({
    configure: (env) => {
      configure(env);
      env.registerVariable("json", "optional<dyn>", {
        description: "HTTP \u54CD\u5E94\u4F53\uFF08\u5DF2\u89E3\u6790 JSON\uFF09\uFF1B\u672A\u914D\u7F6E request \u65F6\u4E3A none"
      });
      extras?.data?.(env);
    },
    resultType: (type) => type.startsWith("list") || type === "dyn" || type.startsWith("optional")
  });
  return Schema.Struct({
    request: Schema.optional(CelRequest).annotations({
      title: "\u8BF7\u6C42",
      description: "\u53EF\u9009\u7684 HTTP \u8BF7\u6C42\u8868\u8FBE\u5F0F\uFF1B\u672A\u914D\u7F6E\u65F6\u6570\u636E\u4ECE `data` \u8868\u8FBE\u5F0F\u4E2D\u8BFB\u53D6\uFF08\u901A\u5E38\u5F15\u7528\u4E0A\u4E0B\u6587\u53D8\u91CF\uFF09"
    }),
    data: CelRows.annotations({
      title: "\u6570\u636E",
      description: "\u8FD4\u56DE\u884C\u6570\u636E\u5217\u8868\uFF08`list<dyn>`\uFF09\u7684 CEL \u8868\u8FBE\u5F0F\uFF1B\u5728\u914D\u7F6E\u4E86 `request` \u65F6\u53EF\u901A\u8FC7 `json` \u5F15\u7528\u54CD\u5E94\u4F53"
    })
  }).annotations({
    title: "DataSource",
    description: "\u6570\u636E\u6E90\u914D\u7F6E"
  });
}
export function tableDataSource(configure) {
  const CelRequest = Expression({
    configure: (env) => {
      configure(env);
      registerDataSourceRequestVars(env);
    },
    resultType: HttpRequestResult
  });
  const CelRows = Expression({
    configure: (env) => {
      configure(env);
      registerDataSourceResponseVars(env);
    },
    resultType: (type) => type.startsWith("list") || type === "dyn" || type.startsWith("optional")
  });
  const CelTotal = Expression({
    configure: (env) => {
      configure(env);
      registerDataSourceResponseVars(env);
    },
    resultType: (type) => type === "number" || type === "dyn" || type.startsWith("optional")
  });
  return Schema.Struct({
    request: Schema.optional(CelRequest).annotations({
      title: "\u8BF7\u6C42",
      description: "\u53EF\u9009\u7684 HTTP \u8BF7\u6C42\u8868\u8FBE\u5F0F\uFF1B\u672A\u914D\u7F6E\u65F6\u6570\u636E\u4ECE `data` \u8868\u8FBE\u5F0F\u4E2D\u8BFB\u53D6\uFF08\u901A\u5E38\u5F15\u7528\u4E0A\u4E0B\u6587\u53D8\u91CF\uFF09"
    }),
    data: CelRows.annotations({
      title: "\u6570\u636E",
      description: "\u8FD4\u56DE\u884C\u6570\u636E\u5217\u8868\uFF08`list<dyn>`\uFF09\u7684 CEL \u8868\u8FBE\u5F0F\uFF1B\u5728\u914D\u7F6E\u4E86 `request` \u65F6\u53EF\u901A\u8FC7 `json` \u5F15\u7528\u54CD\u5E94\u4F53"
    }),
    total: Schema.optional(CelTotal).annotations({
      title: "\u603B\u6570",
      description: "\u8FD4\u56DE\u603B\u884C\u6570\uFF08`number`\uFF09\u7684 CEL \u8868\u8FBE\u5F0F\uFF1B\u914D\u7F6E\u540E\u542F\u7528\u670D\u52A1\u7AEF\u5206\u9875\uFF0C\u7559\u7A7A\u5219\u8D70\u524D\u7AEF\u5206\u9875"
    })
  }).annotations({
    title: "DataSource",
    description: "\u6570\u636E\u6E90\u914D\u7F6E"
  });
}
export function TableConfig(configure) {
  const columnSchemas = allColumnSchemas(configure);
  if (columnSchemas.length === 0) {
    throw new Error("[shwfed-table] no columns registered under columns/<date>/<id>/");
  }
  const ColumnSchema = (columnSchemas.length === 1 ? columnSchemas[0] : Schema.Union(...columnSchemas)).annotations({
    title: "Column",
    description: "\u5217\u5B9A\u4E49\uFF0C\u7531 `type` \u5B57\u6BB5\u533A\u5206\u7C7B\u578B"
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
  });
  const CelCellStyle = Expression({
    configure: (env) => {
      configure(env);
      registerRowVariablesIfAbsent(env);
      env.registerVariable("id", "string", { description: "\u5217 ID" });
      env.registerVariable("selected", "bool", { description: "\u884C\u662F\u5426\u9009\u4E2D" });
      env.registerVariable("pinned", "dyn", { description: "\u5217\u56FA\u5B9A\u72B6\u6001" });
    },
    resultType: (type) => type.startsWith("map")
  });
  const CelRowKey = CelRowAccess(configure, {
    resultType: (type) => type === "string" || type === "number" || type === "dyn"
  });
  const dataSourceSchema = tableDataSource(configure);
  const { fields: actionFields } = ActionSchemaFields((env) => configureTableActionsScope(env, configure));
  const TableActions = Schema.Struct(actionFields).annotations({
    title: "TableActions",
    description: "\u8868\u683C\u7EA7\u64CD\u4F5C\u6309\u94AE"
  });
  const Query = FormConfig(configure);
  return Schema.Struct({
    kind: Schema.tag(KIND),
    id: Schema.optional(Schema.UUID.annotations({
      description: "\u8868\u683C\u5B9E\u4F8B\u552F\u4E00\u6807\u8BC6\uFF1B\u4F5C\u4E3A\u4E8B\u4EF6\u76EE\u6807\u88AB op-request \u5F15\u7528"
    })),
    displayName: Schema.optional(Schema.String.annotations({
      title: "\u5185\u90E8\u540D\u79F0",
      description: "\u4EC5\u5728\u914D\u7F6E\u754C\u9762\u53EF\u89C1\u7684\u8868\u683C\u540D\u79F0\uFF0C\u7528\u4E8E\u5728\u4E8B\u4EF6\u76EE\u6807\u7B49\u4F4D\u7F6E\u6807\u8BC6\u8BE5\u8868\u683C\uFF1B\u8FD0\u884C\u65F6\u4E0D\u5C55\u793A"
    })),
    columns: Schema.Array(ColumnSchema).annotations({
      description: "\u5217\u5B9A\u4E49\u5217\u8868"
    }),
    groups: Schema.optionalWith(Schema.Array(ColumnGroup), { default: () => [] }).annotations({
      title: "\u5217\u5206\u7EC4",
      description: "\u5217\u5206\u7EC4\u5217\u8868"
    }),
    // Optional so a host that drives rows directly (the `table` form field's
    // `v-model:rows` binding) can omit it — `fetchDataSource` short-circuits
    // when undefined, leaving rows fully owned by the host's model.
    dataSource: Schema.optional(dataSourceSchema.annotations({
      title: "\u6570\u636E\u6E90",
      description: "\u6570\u636E\u6E90\u914D\u7F6E"
    })),
    actions: Schema.optional(TableActions).annotations({
      title: "\u4E0A\u65B9\u64CD\u4F5C",
      description: "\u6E32\u67D3\u5728\u8868\u683C\u4E0A\u65B9\u7684\u64CD\u4F5C\u6309\u94AE"
    }),
    bottomActions: Schema.optional(TableActions).annotations({
      title: "\u4E0B\u65B9\u64CD\u4F5C",
      description: "\u6E32\u67D3\u5728\u8868\u683C\uFF08\u542B\u5206\u9875\u5668\uFF09\u4E0B\u65B9\u7684\u64CD\u4F5C\u6309\u94AE\uFF1B\u4E0E\u4E0A\u65B9\u64CD\u4F5C\u5171\u4EAB\u540C\u4E00\u4F5C\u7528\u57DF\uFF08`selected` / `query` / `sorts`\uFF09"
    }),
    query: Schema.optional(Query).annotations({
      title: "\u641C\u7D22\u6761\u4EF6",
      description: "\u6E32\u67D3\u5728\u8868\u683C\u4E0A\u65B9\u7684\u641C\u7D22\u6761\u4EF6\u8868\u5355\uFF1B\u5176\u5F53\u524D\u503C\u4EE5 `query` \u53D8\u91CF\u6CE8\u5165\u6570\u636E\u6E90\u8868\u8FBE\u5F0F"
    }),
    rowKey: Schema.optional(CelRowKey).annotations({
      title: "\u884C\u552F\u4E00\u6807\u8BC6",
      description: "\u4E3A\u6BCF\u4E00\u884C\u8BA1\u7B97\u7A33\u5B9A\u552F\u4E00 ID \u7684 CEL \u8868\u8FBE\u5F0F\uFF0C\u53EF\u8BBF\u95EE `row` / `index`\uFF0C\u7ED3\u679C\u987B\u4E3A\u5B57\u7B26\u4E32\u6216\u6570\u5B57\uFF08\u4F8B\u5982 `row.id`\uFF09\u3002\u914D\u7F6E\u540E\uFF0C\u8DE8\u5237\u65B0\u7684\u52FE\u9009\u3001\u5C55\u5F00\u7B49\u884C\u7EA7\u72B6\u6001\u6309\u8BE5 ID \u5339\u914D\uFF1B\u7559\u7A7A\u65F6\u884C\u8EAB\u4EFD\u6309\u5BF9\u8C61\u5F15\u7528\u515C\u5E95\uFF0C\u8FDC\u7AEF\u6570\u636E\u5237\u65B0\u4F1A\u4E22"
    }),
    cellStyle: Schema.optional(CelCellStyle).annotations({
      title: "\u5355\u5143\u683C\u6837\u5F0F",
      description: "\u5355\u5143\u683C\u6837\u5F0F CEL \u8868\u8FBE\u5F0F"
    }),
    style: Schema.optional(Schema.String).annotations({
      title: "\u5BB9\u5668\u6837\u5F0F",
      description: "\u5E94\u7528\u5728\u8868\u683C\u6700\u5916\u5C42\u5BB9\u5668\u4E0A\u7684 CSS \u6837\u5F0F\u5B57\u7B26\u4E32"
    }),
    pagination: Schema.optional(Pagination).annotations({
      title: "\u5206\u9875"
    }),
    persistQuery: Schema.optional(Schema.Boolean.annotations({
      title: "\u4FDD\u7559\u641C\u7D22\u6761\u4EF6",
      description: "\u6253\u5F00\u540E\uFF0C\u641C\u7D22\u6761\u4EF6\u4EC5\u5728\u7528\u6237\u5173\u95ED\u5F53\u524D\u9875\u7B7E\u65F6\u6E05\u7A7A"
    })),
    initialState: Schema.optional(InitialState)
  }).pipe(Schema.filter((cfg) => {
    if (cfg.dataSource?.total !== void 0 && cfg.pagination === void 0) {
      return "\u914D\u7F6E\u4E86 dataSource.total \u65F6\u5FC5\u987B\u542F\u7528\u5206\u9875";
    }
    for (const col of cfg.columns) {
      const c = col;
      if (c.enableSorting === true && (c.sortKey === void 0 || c.sortKey.length === 0)) {
        return "\u542F\u7528\u6392\u5E8F\u7684\u5217\u5FC5\u987B\u586B\u5199\u300C\u6392\u5E8F\u5B57\u6BB5\u300D(sortKey)";
      }
    }
    return true;
  })).annotations({
    title: "TableConfig",
    description: "\u8868\u683C\u7EC4\u4EF6\u5B8C\u6574\u914D\u7F6E"
  });
}
export function createTableConfig(body) {
  return {
    kind: KIND,
    ...body
  };
}
export function defaultTableConfig() {
  return {
    kind: KIND,
    id: crypto.randomUUID(),
    columns: [],
    groups: [],
    dataSource: { data: "[]" },
    pagination: {
      pageSizes: [100, 200, 500, 1e3],
      pageIndex: 0,
      pageSize: 100
    },
    cellStyle: `selected
  ? { 'background-color': 'color-mix(in srgb, var(--primary) 10%, white) !important' }
  : index % 2 == 1 ? { 'background-color': 'oklch(98.5% 0 0)' } : { 'background-color': 'white' }`
  };
}
export function getColumnTechnicalKey(column) {
  return column.id;
}
