import { Schema } from "effect";
import { Expression, HttpRequestResult } from "../../share/expression.js";
import { allFieldSchemas } from "./utils/resolve.js";
import { registerFormVariablesIfAbsent } from "./utils/form-vars.js";
import { md } from "../../share/markdown.js";
import {
  LayoutSet,
  validatePlacements
} from "../../share/layout.js";
export { commonFieldFields } from "./utils/common.js";
export {
  getStructFieldTitle,
  getStructFieldDescription,
  getNestedStructFieldTitle,
  getNestedStructFieldDescription
} from "./utils/schema-meta.js";
export { Align, DEFAULT_GAP, LayoutSet, validatePlacements } from "../../share/layout.js";
const KIND = "shwfed.component.form";
export const metadata = {
  name: "\u8868\u5355",
  icon: "fluent:form-20-regular",
  operations: [
    { id: "validate", name: "\u6821\u9A8C", icon: "fluent:checkmark-circle-20-regular" },
    { id: "undo", name: "\u64A4\u9500", icon: "fluent:arrow-undo-20-regular" },
    { id: "redo", name: "\u91CD\u505A", icon: "fluent:arrow-redo-20-regular" },
    { id: "reset-to-initial", name: "\u91CD\u7F6E\u4E3A\u521D\u59CB\u503C", icon: "fluent:arrow-reset-20-regular" }
  ]
};
function unitFields(configure) {
  const fieldSchemas = allFieldSchemas(configure);
  const Field = fieldSchemas.length === 0 ? Schema.Never : fieldSchemas.length === 1 ? fieldSchemas[0] : Schema.Union(...fieldSchemas);
  const AnnotatedField = Field.annotations({
    description: "\u8868\u5355\u5B57\u6BB5\uFF0C\u7531 `type` \u5B57\u6BB5\u533A\u5206\u7C7B\u578B"
  });
  return {
    fields: Schema.Array(AnnotatedField).annotations({
      title: "\u5B57\u6BB5",
      description: "\u8868\u5355\u5B57\u6BB5\u5217\u8868\uFF1B\u672A\u7ED1\u5B9A\u5230\u4EFB\u4F55\u5E03\u5C40\u7684\u5B57\u6BB5\u4E0D\u4F1A\u88AB\u6E32\u67D3"
    }),
    layouts: Schema.Array(LayoutSet(configure)).pipe(Schema.minItems(1)).annotations({
      title: "\u5E03\u5C40",
      description: "\u6309\u987A\u5E8F\u6392\u5217\u7684\u5E03\u5C40\u96C6\u5408\uFF1B\u6302\u8F7D\u65F6\u6309\u5E8F\u6C42\u503C\u5404\u9879 `media` CEL \u8868\u8FBE\u5F0F\uFF0C\u4F7F\u7528\u7B2C\u4E00\u4E2A\u4E3A `true` \u7684\u5E03\u5C40\uFF08\u5168\u90E8\u4E0D\u5339\u914D\u65F6\u56DE\u9000\u5230\u6700\u540E\u4E00\u9879\uFF09"
    })
  };
}
function unitPlacementsFilter(cfg) {
  const items = cfg.fields.map((f) => ({ id: f.id }));
  return validatePlacements(items, cfg.layouts, "\u5B57\u6BB5");
}
export function FormUnit(configure) {
  return Schema.Struct(unitFields(configure)).pipe(Schema.filter(unitPlacementsFilter)).annotations({
    title: "FormUnit",
    description: "\u4E00\u7EC4\u8868\u5355\u5B57\u6BB5\u53CA\u5176\u5E03\u5C40"
  });
}
export { registerFormVariablesIfAbsent };
export function FormConfig(configure) {
  const formConfigure = (env) => {
    registerFormVariablesIfAbsent(env);
    configure(env);
  };
  const CelInitialRequest = Expression({ configure: formConfigure, resultType: HttpRequestResult });
  const CelInitialData = Expression({
    configure: (env) => {
      formConfigure(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\uFF0C\u7528 `json.?\u5B57\u6BB5` \u8BBF\u95EE"
      });
    },
    resultType: "dyn"
  });
  const CelFormReadonly = Expression({ configure: formConfigure, resultType: "bool" });
  const InitialStruct = Schema.Struct({
    request: Schema.optional(CelInitialRequest.annotations({
      title: "\u8BF7\u6C42",
      description: md`
        可选的 HTTP 请求表达式：返回 \`HttpRequest\`，运行时由宿主发起，并把响应体作为 \`json\` 传给「数据」表达式。

        留空时「数据」直接对 CEL 上下文求值（静态默认值，或引用 \`form\` 的表达式）。
      `
    })),
    data: CelInitialData.annotations({
      title: "\u6570\u636E",
      description: md`
        返回整个表单初始值的 CEL 表达式（应为一个对象）：

        - 可以互相依赖，但应避免循环引用。考虑一个含「用户名」与「用户角色」的表单：可默认填入当前登入人的用户名，再以此为依据填入其默认角色。

        - 配置了「请求」时，可通过 \`json\` 引用响应体，例如 \`json.?data\`。

        - 如果配置了初始值，重置这个表单将**重置为其初始值，而非空**。
      `
    })
  });
  const Initial = Schema.transform(
    Schema.Union(CelInitialData, InitialStruct),
    InitialStruct,
    {
      strict: true,
      decode: (input) => typeof input === "string" ? { data: input } : input,
      encode: (output) => output
    }
  );
  return Schema.Struct({
    kind: Schema.tag(KIND),
    id: Schema.optional(Schema.UUID.annotations({
      description: "\u8868\u5355\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\u5355\u540D\u79F0\uFF0C\u7528\u4E8E\u5728\u4E8B\u4EF6\u76EE\u6807\u7B49\u4F4D\u7F6E\u6807\u8BC6\u8BE5\u8868\u5355\uFF1B\u8FD0\u884C\u65F6\u4E0D\u5C55\u793A"
    })),
    initial: Schema.optional(Initial.annotations({
      title: "\u521D\u59CB\u503C",
      description: "\u8868\u5355\u521D\u59CB\u503C\u7684\u6765\u6E90\uFF1A\u53EF\u9009\u7684 HTTP \u8BF7\u6C42\uFF0C\u52A0\u4E00\u4E2A\u8FD4\u56DE\u521D\u59CB\u503C\u5BF9\u8C61\u7684 CEL \u8868\u8FBE\u5F0F"
    })),
    readonly: Schema.optional(CelFormReadonly.annotations({
      title: "\u53EA\u8BFB\u6761\u4EF6",
      description: md`
        返回 \`true\` 时整个表单切到只读：所有字段以纯文本展示、不可编辑。

        可访问 \`form\` 当前状态，因此可让表单按数据自锁——例如 \`form.status == 'submitted'\`，新建时可填、载入已提交的记录后只读。

        字段自身的「只读条件」会**覆盖**这里：未配置只读条件的字段跟随本表达式，配置了的以字段自己的结果为准（可在只读表单中单独放开某个字段）。
      `
    })),
    style: Schema.optional(Schema.String).annotations({
      title: "\u5BB9\u5668\u6837\u5F0F",
      description: "\u5E94\u7528\u5728\u8868\u5355\u6700\u5916\u5C42\u5BB9\u5668\u4E0A\u7684 CSS \u6837\u5F0F\u5B57\u7B26\u4E32"
    }),
    ...unitFields(formConfigure)
  }).pipe(Schema.filter(unitPlacementsFilter)).annotations({
    title: "FormConfig",
    description: "Form \u7EC4\u4EF6\u5B8C\u6574\u914D\u7F6E"
  });
}
export function createFormConfig(body) {
  return { kind: KIND, ...body };
}
export function defaultFormConfig() {
  return {
    kind: KIND,
    id: crypto.randomUUID(),
    fields: [],
    layouts: [{ name: "\u9ED8\u8BA4", layout: { columns: 1, placements: {} } }]
  };
}
