"use client";

import {
  CheckCircle2,
  ChevronDown,
  ChevronUp,
  Copy,
  Eye,
  EyeOff,
  Loader2,
  MoreHorizontal,
  Pencil,
  Plug,
  Plus,
  Trash2,
  XCircle,
} from "lucide-react";
import { useCallback, useEffect, useMemo, useState } from "react";

import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { DataList } from "@/components/ui/data-list";
import { PageHeader } from "@/components/ui/page-header";
import { FilterPills } from "@/components/ui/filter-pills";
import { SearchInput } from "@/components/ui/search-input";
import { ListToolbar } from "@/components/ui/list-toolbar";
import { Input } from "@/components/ui/input";
import { Switch } from "@/components/ui/switch";
import { Textarea } from "@/components/ui/textarea";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import {
  interfaceDefinitionsApi,
  modelResourcesApi,
  type InterfaceDefinition,
  type InterfaceField,
  type ModelResource,
  type ModelType,
} from "@/lib/api";

const capabilities: ModelType[] = [
  "LLM",
  "ASR",
  "TTS",
  "Realtime",
  "Embedding",
  "Agent",
];

const capabilityFilters = ["全部", ...capabilities] as const;

type ResourceDraft = {
  name: string;
  capability: ModelType;
  interfaceType: string;
  values: Record<string, unknown>;
  secrets: Record<string, unknown>;
  supportImageInput: boolean;
};

const emptyDraft: ResourceDraft = {
  name: "",
  capability: "LLM",
  interfaceType: "",
  values: {},
  secrets: {},
  supportImageInput: false,
};

function defaults(definition: InterfaceDefinition): Record<string, unknown> {
  return Object.fromEntries(
    definition.fieldSchema.fields
      .filter((field) => field.group === "values" && field.default !== undefined)
      .map((field) => [field.key, field.default]),
  );
}

function formatUpdatedAt(value?: string | null): string {
  if (!value) return "—";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return "—";
  return date.toLocaleString("zh-CN", {
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
    hour: "2-digit",
    minute: "2-digit",
  });
}

// 列表按更新时间排序:newest=最近更新在前(倒叙,默认) / oldest=最早更新在前
type SortOrder = "newest" | "oldest";

// 缺失/非法时间戳视为最早(0),用于排序
function updatedAtValue(value?: string | null): number {
  const time = value ? new Date(value).getTime() : NaN;
  return Number.isNaN(time) ? 0 : time;
}

function fieldValue(draft: ResourceDraft, field: InterfaceField): unknown {
  return field.group === "secrets"
    ? draft.secrets[field.key]
    : draft.values[field.key];
}

function secretMask(
  masks: Record<string, unknown>,
  field: InterfaceField,
): string {
  if (field.group !== "secrets") return "";
  const value = masks[field.key];
  return typeof value === "string" && value.includes("****") ? value : "";
}

function extraBodyText(values: Record<string, unknown>): string {
  const value = values.extraBody;
  if (!value || typeof value !== "object" || Array.isArray(value)) return "";
  return JSON.stringify(value, null, 2);
}

function parseExtraBody(text: string):
  | { ok: true; value: Record<string, unknown> | null }
  | { ok: false; error: string } {
  const trimmed = text.trim();
  if (!trimmed) return { ok: true, value: null };
  try {
    const parsed = JSON.parse(trimmed) as unknown;
    if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
      return { ok: false, error: "Extra Body 必须是 JSON 对象" };
    }
    return { ok: true, value: parsed as Record<string, unknown> };
  } catch {
    return { ok: false, error: "Extra Body 不是合法 JSON" };
  }
}

function valuesWithExtraBody(
  values: Record<string, unknown>,
  extraBody: Record<string, unknown> | null,
): Record<string, unknown> {
  const next = { ...values };
  delete next.extraBody;
  if (extraBody) next.extraBody = extraBody;
  return next;
}

function isSelectableDefinition(definition: InterfaceDefinition): boolean {
  return (
    definition.capability !== "LLM" || definition.interfaceType === "openai-llm"
  );
}

export function ComponentsModelsPage() {
  const [resources, setResources] = useState<ModelResource[]>([]);
  const [definitions, setDefinitions] = useState<InterfaceDefinition[]>([]);
  const [loading, setLoading] = useState(true);
  const [loadError, setLoadError] = useState("");
  const [search, setSearch] = useState("");
  const [filter, setFilter] = useState<ModelType | "全部">("全部");
  const [sortOrder, setSortOrder] = useState<SortOrder>("newest");
  const [currentPage, setCurrentPage] = useState(1);

  const [dialogOpen, setDialogOpen] = useState(false);
  const [editingId, setEditingId] = useState<string | null>(null);
  const [draft, setDraft] = useState<ResourceDraft>(emptyDraft);
  const [storedSecretMasks, setStoredSecretMasks] = useState<Record<string, unknown>>({});
  const [extraBodyDraft, setExtraBodyDraft] = useState("");
  const [saving, setSaving] = useState(false);
  const [saveError, setSaveError] = useState("");
  const [testing, setTesting] = useState(false);
  const [testResult, setTestResult] = useState<{
    ok: boolean;
    message: string;
  } | null>(null);
  const [deletingId, setDeletingId] = useState<string | null>(null);
  const [duplicatingId, setDuplicatingId] = useState<string | null>(null);

  const load = useCallback(async () => {
    setLoading(true);
    setLoadError("");
    try {
      const [nextResources, nextDefinitions] = await Promise.all([
        modelResourcesApi.list(),
        interfaceDefinitionsApi.list(),
      ]);
      setResources(nextResources);
      setDefinitions(nextDefinitions);
    } catch (error) {
      setLoadError(error instanceof Error ? error.message : "加载失败");
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    // Initial external API synchronization.
    // eslint-disable-next-line react-hooks/set-state-in-effect
    void load();
  }, [load]);

  const selectableDefinitions = definitions.filter(isSelectableDefinition);
  const availableDefinitions = selectableDefinitions.filter(
    (definition) => definition.capability === draft.capability,
  );
  const selectedDefinition = definitions.find(
    (definition) => definition.interfaceType === draft.interfaceType,
  );
  const connectionFields =
    selectedDefinition?.fieldSchema.fields.filter(
      (field) => field.group === "secrets" || field.required,
    ) ?? [];
  const optionalFields =
    selectedDefinition?.fieldSchema.fields.filter(
      (field) => field.group === "values" && !field.required,
    ) ?? [];

  const filtered = useMemo(() => {
    const keyword = search.trim().toLowerCase();
    return resources.filter((resource) => {
      if (filter !== "全部" && resource.capability !== filter) return false;
      return (
        !keyword ||
        [
          resource.name,
          resource.interfaceType,
          String(resource.values.modelId ?? ""),
        ]
          .join(" ")
          .toLowerCase()
          .includes(keyword)
      );
    });
  }, [resources, search, filter]);

  // 按更新时间排序(以原始时间戳为准);id 作为稳定的次级排序键
  const sorted = useMemo(() => {
    return [...filtered].sort((a, b) => {
      const diff = updatedAtValue(b.updatedAt) - updatedAtValue(a.updatedAt);
      if (diff !== 0) return sortOrder === "newest" ? diff : -diff;
      return a.id.localeCompare(b.id);
    });
  }, [filtered, sortOrder]);

  const pageSize = 5;
  const totalPages = Math.max(1, Math.ceil(sorted.length / pageSize));
  const safeCurrentPage = Math.min(currentPage, totalPages);
  const pageStart = (safeCurrentPage - 1) * pageSize;
  const pageEnd = pageStart + pageSize;
  const paginatedResources = sorted.slice(pageStart, pageEnd);

  function changeFilter(nextFilter: ModelType | "全部") {
    setFilter(nextFilter);
    setCurrentPage(1);
  }

  function changeSearch(value: string) {
    setSearch(value);
    setCurrentPage(1);
  }

  function changeSort(order: SortOrder) {
    setSortOrder(order);
    setCurrentPage(1);
  }

  function toggleSortOrder() {
    changeSort(sortOrder === "newest" ? "oldest" : "newest");
  }

  function selectDefinition(interfaceType: string) {
    const definition = definitions.find(
      (item) => item.interfaceType === interfaceType,
    );
    setDraft((previous) => ({
      ...previous,
      interfaceType,
      values: definition ? defaults(definition) : {},
      secrets: {},
    }));
    setStoredSecretMasks({});
    setExtraBodyDraft("");
    setTestResult(null);
  }

  function selectCapability(capability: ModelType) {
    const first = selectableDefinitions.find(
      (definition) => definition.capability === capability,
    );
    setDraft((previous) => ({
      ...previous,
      capability,
      interfaceType: first?.interfaceType ?? "",
      values: first ? defaults(first) : {},
      secrets: {},
      supportImageInput:
        capability === "LLM" ? previous.supportImageInput : false,
    }));
    setStoredSecretMasks({});
    setExtraBodyDraft("");
    setTestResult(null);
  }

  function openCreate() {
    const first = selectableDefinitions.find(
      (definition) => definition.capability === "LLM",
    );
    setEditingId(null);
    setDraft({
      ...emptyDraft,
      interfaceType: first?.interfaceType ?? "",
      values: first ? defaults(first) : {},
      secrets: {},
      supportImageInput: false,
    });
    setStoredSecretMasks({});
    setExtraBodyDraft("");
    setSaveError("");
    setTestResult(null);
    setDialogOpen(true);
  }

  function openEdit(resource: ModelResource) {
    setEditingId(resource.id);
    setDraft({
      name: resource.name,
      capability: resource.capability,
      interfaceType: resource.interfaceType,
      values: resource.values,
      secrets: {},
      supportImageInput: resource.supportImageInput,
    });
    setStoredSecretMasks(resource.secrets);
    setExtraBodyDraft(extraBodyText(resource.values));
    setSaveError("");
    setTestResult(null);
    setDialogOpen(true);
  }

  function updateField(field: InterfaceField, value: unknown) {
    const target = field.group === "secrets" ? "secrets" : "values";
    setDraft((previous) => ({
      ...previous,
      [target]: { ...previous[target], [field.key]: value },
    }));
    setTestResult(null);
  }

  const parsedExtraBody = parseExtraBody(extraBodyDraft);
  const extraBodyError = parsedExtraBody.ok ? "" : parsedExtraBody.error;
  const canSave = Boolean(
    draft.name.trim() &&
      selectedDefinition &&
      !extraBodyError &&
      selectedDefinition.fieldSchema.fields.every((field) => {
        if (!field.required) return true;
        const value =
          field.group === "secrets" && secretMask(storedSecretMasks, field)
            ? secretMask(storedSecretMasks, field)
            : fieldValue(draft, field);
        return value !== undefined && value !== null && value !== "";
      }),
  );

  function payload() {
    const extraBody = parsedExtraBody.ok ? parsedExtraBody.value : null;
    return {
      name: draft.name.trim(),
      interfaceType: draft.interfaceType,
      values:
        draft.capability === "LLM"
          ? valuesWithExtraBody(draft.values, extraBody)
          : draft.values,
      secrets: editingId
        ? { ...storedSecretMasks, ...draft.secrets }
        : draft.secrets,
      supportImageInput:
        draft.capability === "LLM" ? draft.supportImageInput : false,
      enabled: editingId
        ? resources.find((resource) => resource.id === editingId)?.enabled ?? true
        : true,
      isDefault: editingId
        ? resources.find((resource) => resource.id === editingId)?.isDefault ?? false
        : false,
    };
  }

  async function testConnection() {
    if (!canSave) return;
    setTesting(true);
    setTestResult(null);
    try {
      const result = await modelResourcesApi.test(payload(), editingId ?? undefined);
      setTestResult({
        ok: result.ok,
        message: [
          result.message,
          result.latencyMs !== null ? `${result.latencyMs}ms` : "",
          result.detail,
        ]
          .filter(Boolean)
          .join(" · "),
      });
    } catch (error) {
      setTestResult({
        ok: false,
        message: error instanceof Error ? error.message : "测试连接失败",
      });
    } finally {
      setTesting(false);
    }
  }

  async function save() {
    if (!canSave) return;
    setSaving(true);
    setSaveError("");
    const body = payload();
    try {
      if (editingId) {
        await modelResourcesApi.update(editingId, body);
      } else {
        await modelResourcesApi.create(body);
      }
      setDialogOpen(false);
      await load();
    } catch (error) {
      setSaveError(error instanceof Error ? error.message : "保存失败");
    } finally {
      setSaving(false);
    }
  }

  async function remove(id: string) {
    setDeletingId(id);
    try {
      await modelResourcesApi.remove(id);
      await load();
    } catch (error) {
      setLoadError(error instanceof Error ? error.message : "删除失败");
    } finally {
      setDeletingId(null);
    }
  }

  async function duplicate(id: string) {
    setDuplicatingId(id);
    try {
      await modelResourcesApi.duplicate(id);
      await load();
    } catch (error) {
      setLoadError(error instanceof Error ? error.message : "复制失败");
    } finally {
      setDuplicatingId(null);
    }
  }

  return (
    <div className="mx-auto flex w-full max-w-[1440px] flex-col gap-8">
      <PageHeader
        title="模型资源"
        description="接口定义决定能力、鉴权字段和调用参数，表单会随接口类型动态更新。"
        action={
          <Button
            size="lg"
            className="w-full gap-2 sm:w-auto"
            onClick={openCreate}
          >
            <Plus size={16} />
            添加模型
          </Button>
        }
      />

      <section className="rounded-2xl border border-hairline bg-card p-6 shadow-sm">
        <ListToolbar
          filters={
            <FilterPills
              options={capabilityFilters}
              value={filter}
              onChange={changeFilter}
            />
          }
          search={
            <SearchInput
              value={search}
              onChange={changeSearch}
              placeholder="搜索名称、接口类型或模型 ID"
              className="lg:w-[320px]"
            />
          }
        />

        <DataList<ModelResource>
          rows={paginatedResources}
          rowKey={(resource) => resource.id}
          loading={loading}
          error={loadError || null}
          onRetry={() => void load()}
          empty={{
            title:
              resources.length === 0
                ? "暂无模型资源"
                : "未找到匹配的模型资源",
            description:
              resources.length === 0
                ? "点击右上角「添加模型」开始。"
                : "请调整关键词或筛选条件后再试。",
          }}
          pagination={{
            page: safeCurrentPage,
            totalPages,
            onPageChange: setCurrentPage,
            summary:
              filtered.length === 0
                ? "没有数据"
                : `显示 ${pageStart + 1}-${Math.min(pageEnd, filtered.length)} / 共 ${filtered.length} 个模型资源`,
          }}
          columns={[
            {
              key: "name",
              header: "模型名称",
              width: "md:w-[360px]",
              cell: (resource) => (
                <>
                  <div className="flex min-w-0 items-center gap-2">
                    <span className="truncate font-medium text-foreground">
                      {resource.name}
                    </span>
                    {resource.supportImageInput && (
                      <span
                        className="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-surface-strong text-muted-foreground"
                        title="支持图片输入"
                        aria-label="支持图片输入"
                      >
                        <Eye size={12} />
                      </span>
                    )}
                  </div>
                  <div className="mt-1 truncate text-xs text-muted-soft">
                    {String(
                      resource.values.modelId ?? resource.values.apiUrl ?? "",
                    )}
                  </div>
                </>
              ),
            },
            {
              key: "capability",
              header: "能力",
              width: "md:w-[128px]",
              cell: (resource) => (
                <Badge
                  variant="secondary"
                  className="h-6 bg-surface-strong px-3 text-muted-foreground"
                >
                  {resource.capability}
                </Badge>
              ),
            },
            {
              key: "interfaceType",
              header: "接口类型",
              width: "md:w-[220px]",
              cell: (resource) => (
                <Badge variant="outline" className="h-6 px-3">
                  {resource.interfaceType}
                </Badge>
              ),
            },
            {
              key: "updatedAt",
              width: "md:w-[176px]",
              header: (
                <button
                  type="button"
                  onClick={toggleSortOrder}
                  className="caption-label -mx-2 inline-flex items-center gap-1 rounded-md px-2 py-1 text-muted-soft transition-colors hover:bg-surface-strong hover:text-foreground"
                  aria-label={
                    sortOrder === "newest"
                      ? "当前按最近更新排序,点击切换为最早更新"
                      : "当前按最早更新排序,点击切换为最近更新"
                  }
                >
                  更新时间
                  {sortOrder === "newest" ? (
                    <ChevronDown size={13} />
                  ) : (
                    <ChevronUp size={13} />
                  )}
                </button>
              ),
              cellClassName:
                "whitespace-nowrap tabular-nums text-muted-foreground",
              cell: (resource) => formatUpdatedAt(resource.updatedAt),
            },
            {
              key: "actions",
              header: "操作",
              align: "right",
              cellClassName: "flex justify-end gap-2",
              cell: (resource) => (
                <>
                  <Button
                    variant="outline"
                    size="sm"
                    className="gap-1.5 border-hairline-strong text-xs text-muted-foreground hover:text-foreground"
                    onClick={() => openEdit(resource)}
                  >
                    <Pencil size={14} />
                    编辑
                  </Button>
                  <DropdownMenu>
                    <DropdownMenuTrigger asChild>
                      <Button
                        variant="outline"
                        size="icon-sm"
                        className="border-hairline-strong text-muted-foreground hover:text-foreground"
                        aria-label={`${resource.name} 更多操作`}
                      >
                        <MoreHorizontal size={15} />
                      </Button>
                    </DropdownMenuTrigger>
                    <DropdownMenuContent
                      align="end"
                      className="w-32 min-w-32 rounded-xl border border-hairline bg-popover p-1"
                    >
                      <DropdownMenuItem
                        className="rounded-lg"
                        disabled={duplicatingId === resource.id}
                        onSelect={(event) => {
                          event.preventDefault();
                          void duplicate(resource.id);
                        }}
                      >
                        {duplicatingId === resource.id ? (
                          <Loader2 size={14} className="animate-spin" />
                        ) : (
                          <Copy size={14} />
                        )}
                        复制
                      </DropdownMenuItem>
                      <DropdownMenuItem
                        variant="destructive"
                        className="rounded-lg"
                        disabled={deletingId === resource.id}
                        onSelect={(event) => {
                          event.preventDefault();
                          void remove(resource.id);
                        }}
                      >
                        {deletingId === resource.id ? (
                          <Loader2 size={14} className="animate-spin" />
                        ) : (
                          <Trash2 size={14} />
                        )}
                        删除
                      </DropdownMenuItem>
                    </DropdownMenuContent>
                  </DropdownMenu>
                </>
              ),
            },
          ]}
        />
      </section>

      <Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
        <DialogContent className="max-h-[calc(100vh-3rem)] overflow-y-auto sm:max-w-6xl lg:max-w-[88rem] lg:overflow-hidden">
          <DialogHeader>
            <DialogTitle>{editingId ? "编辑模型资源" : "添加模型资源"}</DialogTitle>
            <DialogDescription>
              选择具体接口类型后，系统会从接口定义生成需要填写的字段。修改能力类型会自动取消不再兼容的助手绑定。
            </DialogDescription>
          </DialogHeader>

          <div className="grid gap-5 lg:grid-cols-2">
            <div className="space-y-5 lg:flex lg:h-[38rem] lg:flex-col lg:space-y-0 lg:gap-5">
              <FieldSection title="基本信息">
                <Field label="资源名称" required>
                  <Input
                    value={draft.name}
                    onChange={(event) =>
                      setDraft((previous) => ({
                        ...previous,
                        name: event.target.value,
                      }))
                    }
                  />
                </Field>
                <div className="grid gap-4 sm:grid-cols-2">
                  <Field label="能力类型" required>
                    <Select
                      value={draft.capability}
                      onValueChange={(value) =>
                        selectCapability(value as ModelType)
                      }
                    >
                      <SelectTrigger className="w-full">
                        <SelectValue />
                      </SelectTrigger>
                      <SelectContent>
                        {capabilities.map((capability) => (
                          <SelectItem key={capability} value={capability}>
                            {capability}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </Field>
                  <Field label="接口类型" required>
                    <Select
                      value={draft.interfaceType}
                      onValueChange={selectDefinition}
                    >
                      <SelectTrigger className="w-full">
                        <SelectValue placeholder="请选择接口类型" />
                      </SelectTrigger>
                      <SelectContent>
                        {availableDefinitions.map((definition) => (
                          <SelectItem
                            key={definition.interfaceType}
                            value={definition.interfaceType}
                          >
                            {definition.name}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </Field>
                </div>
                {draft.capability === "LLM" && (
                  <div className="flex items-center justify-between rounded-xl border border-hairline p-4">
                    <span className="text-sm font-medium">支持图片输入</span>
                    <Switch
                      checked={draft.supportImageInput}
                      onCheckedChange={(checked) =>
                        setDraft((previous) => ({
                          ...previous,
                          supportImageInput: checked,
                        }))
                      }
                    />
                  </div>
                )}
              </FieldSection>

              <FieldSection title="连接与鉴权信息" scrollable fill>
                {connectionFields.map((field) => (
                  <DynamicField
                    key={`${field.group}-${field.key}`}
                    field={field}
                    value={fieldValue(draft, field)}
                    storedValueMask={secretMask(storedSecretMasks, field)}
                    onChange={(value) => updateField(field, value)}
                  />
                ))}
              </FieldSection>
            </div>

            <FieldSection title="可选项" scrollable tall>
              {draft.capability === "LLM" && (
                <Field label="Extra Body">
                  <Textarea
                    rows={7}
                    value={extraBodyDraft}
                    onChange={(event) => {
                      setExtraBodyDraft(event.target.value);
                      setTestResult(null);
                    }}
                    placeholder={'例如：{\n  "thinking": { "type": "disabled" }\n}'}
                    className="font-mono text-xs leading-5"
                  />
                  {extraBodyError && (
                    <div className="text-xs text-destructive">
                      {extraBodyError}
                    </div>
                  )}
                </Field>
              )}
              {optionalFields.length > 0 ? (
                optionalFields.map((field) => (
                  <DynamicField
                    key={`${field.group}-${field.key}`}
                    field={field}
                    value={fieldValue(draft, field)}
                    storedValueMask={secretMask(storedSecretMasks, field)}
                    onChange={(value) => updateField(field, value)}
                  />
                ))
              ) : draft.capability === "LLM" ? null : (
                <div className="flex h-full items-center justify-center text-sm text-muted-foreground">
                  当前接口没有可选项
                </div>
              )}
            </FieldSection>
          </div>

          {saveError && <div className="text-sm text-destructive">{saveError}</div>}

          <DialogFooter className="sm:items-center sm:justify-between">
            <div className="flex min-w-0 items-center gap-3">
              <Button
                variant="outline"
                className="shrink-0 gap-2"
                disabled={!canSave || testing}
                onClick={() => void testConnection()}
              >
                {testing ? (
                  <Loader2 size={14} className="animate-spin" />
                ) : (
                  <Plug size={14} />
                )}
                测试连接
              </Button>
              {testResult && (
                <span
                  className={[
                    "flex min-w-0 items-center gap-1.5 text-xs",
                    testResult.ok ? "text-emerald-500" : "text-destructive",
                  ].join(" ")}
                  title={testResult.message}
                >
                  {testResult.ok ? (
                    <CheckCircle2 size={14} className="shrink-0" />
                  ) : (
                    <XCircle size={14} className="shrink-0" />
                  )}
                  <span className="truncate">{testResult.message}</span>
                </span>
              )}
            </div>
            <div className="flex items-center gap-2">
              <Button variant="outline" onClick={() => setDialogOpen(false)}>
                取消
              </Button>
              <Button disabled={!canSave || saving} onClick={() => void save()}>
                {saving && <Loader2 size={14} className="animate-spin" />}
                保存
              </Button>
            </div>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}

function Field({
  label,
  required,
  children,
}: {
  label: string;
  required?: boolean;
  children: React.ReactNode;
}) {
  return (
    <label className="block space-y-2">
      <span className="text-sm font-medium">
        {label}
        {required && <span className="ml-1 text-destructive">*</span>}
      </span>
      {children}
    </label>
  );
}

function FieldSection({
  title,
  scrollable,
  tall,
  fill,
  children,
}: {
  title: string;
  scrollable?: boolean;
  tall?: boolean;
  fill?: boolean;
  children: React.ReactNode;
}) {
  return (
    <section
      className={[
        "rounded-xl border border-hairline bg-surface-strong/20",
        tall ? "lg:flex lg:h-[38rem] lg:flex-col" : "",
        fill ? "lg:flex lg:min-h-0 lg:flex-1 lg:flex-col" : "",
      ].join(" ")}
    >
      <div className="border-b border-hairline px-4 py-3 text-sm font-medium">
        {title}
      </div>
      <div
        className={[
          "space-y-4 p-4",
          scrollable ? "max-h-72 overflow-y-auto" : "",
          tall ? "lg:max-h-none lg:flex-1" : "",
          fill ? "lg:min-h-0 lg:max-h-none lg:flex-1" : "",
        ].join(" ")}
      >
        {children}
      </div>
    </section>
  );
}

function DynamicField({
  field,
  value,
  storedValueMask,
  onChange,
}: {
  field: InterfaceField;
  value: unknown;
  storedValueMask?: string;
  onChange: (value: unknown) => void;
}) {
  const [showPassword, setShowPassword] = useState(false);

  if (field.type === "boolean") {
    return (
      <div className="flex items-center justify-between rounded-xl border border-hairline p-4">
        <span className="text-sm font-medium">{field.label}</span>
        <Button
          type="button"
          size="sm"
          variant={Boolean(value) ? "default" : "outline"}
          onClick={() => onChange(!Boolean(value))}
        >
          {Boolean(value) ? "开启" : "关闭"}
        </Button>
      </div>
    );
  }

  if (field.type === "select") {
    return (
      <Field label={field.label} required={field.required}>
        <Select value={String(value ?? "")} onValueChange={onChange}>
          <SelectTrigger className="w-full">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            {(field.options ?? []).map((option) => (
              <SelectItem key={option} value={option}>
                {option}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </Field>
    );
  }

  if (field.type === "password") {
    const inputValue = String(value ?? "");
    const hasStoredValue = Boolean(storedValueMask);

    return (
      <Field label={field.label} required={field.required}>
        {hasStoredValue && (
          <div className="flex items-center gap-2 text-xs text-muted-foreground">
            <span>当前密钥</span>
            <code className="rounded-md bg-surface-strong px-2 py-1 font-mono text-foreground">
              {storedValueMask}
            </code>
          </div>
        )}
        <div className="relative">
          <Input
            type={showPassword ? "text" : "password"}
            value={inputValue}
            onChange={(event) => {
              const nextValue = event.target.value;
              if (!nextValue) setShowPassword(false);
              onChange(nextValue);
            }}
            placeholder={
              hasStoredValue ? "已配置，留空则保持不变" : undefined
            }
            autoComplete="new-password"
            className="pr-10"
          />
          <button
            type="button"
            disabled={!inputValue}
            onClick={() => setShowPassword((current) => !current)}
            className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-soft transition-colors hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40"
            aria-label={showPassword ? "隐藏密钥" : "显示密钥"}
          >
            {showPassword ? <EyeOff size={16} /> : <Eye size={16} />}
          </button>
        </div>
        {hasStoredValue && (
          <p className="text-xs leading-5 text-muted-foreground">
            仅显示当前密钥首尾用于识别。留空可保持原密钥，输入新值将覆盖原密钥。
          </p>
        )}
      </Field>
    );
  }

  return (
    <Field label={field.label} required={field.required}>
      <Input
        type={
          field.type === "number"
            ? "number"
            : field.type === "url"
              ? "url"
              : "text"
        }
        value={String(value ?? "")}
        onChange={(event) =>
          onChange(
            field.type === "number"
              ? Number(event.target.value)
              : event.target.value,
          )
        }
      />
    </Field>
  );
}
