"use client";

import { Flag, PhoneForwarded, Play, Tag } from "lucide-react";
import { useState } from "react";

import { SectionCard } from "@/components/editor/section-card";
import { DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Switch } from "@/components/ui/switch";
import { Textarea } from "@/components/ui/textarea";

import { ActionNodePanel } from "./ActionNodePanel";
import { AgentNodePanel } from "./AgentNodePanel";
import { NodeSelect, ToolOptionPicker } from "./controls";
import type { RuntimeNodeSpec, WorkflowNodeData } from "../specs";
import type { ModelOption, WorkflowSettings } from "../types";

export function NodeSettingsPanel({
  panel = false,
  spec,
  data,
  toolOptions,
  knowledgeOptions,
  llmOptions,
  asrOptions,
  ttsOptions,
  visionOptions,
  workflowSettings,
  onChange,
}: {
  panel?: boolean;
  spec: RuntimeNodeSpec;
  data: WorkflowNodeData;
  toolOptions: ModelOption[];
  knowledgeOptions: ModelOption[];
  llmOptions: ModelOption[];
  asrOptions: ModelOption[];
  ttsOptions: ModelOption[];
  visionOptions: ModelOption[];
  workflowSettings: WorkflowSettings;
  onChange: (patch: WorkflowNodeData) => void;
}) {
  const [draft, setDraft] = useState<WorkflowNodeData>({ ...data });
  const [argumentsJson, setArgumentsJson] = useState(
    JSON.stringify(data.arguments ?? {}, null, 2),
  );
  const [assignmentsJson, setAssignmentsJson] = useState(
    JSON.stringify(data.resultAssignments ?? {}, null, 2),
  );
  const [jsonError, setJsonError] = useState("");
  const commit = (next: WorkflowNodeData) => {
    setDraft(next);
    onChange(next);
  };
  const set = (key: string, val: unknown) =>
    commit({ ...draft, [key]: val });
  const setPatch = (patch: Partial<WorkflowNodeData>) =>
    commit({ ...draft, ...patch });
  const commitActionJson = (
    nextArgumentsJson: string,
    nextAssignmentsJson: string,
  ) => {
    try {
      const args = JSON.parse(nextArgumentsJson) as Record<string, unknown>;
      const assignments = JSON.parse(nextAssignmentsJson) as Record<string, string>;
      if (Array.isArray(args) || Array.isArray(assignments)) throw new Error();
      setJsonError("");
      commit({ ...draft, arguments: args, resultAssignments: assignments });
    } catch {
      setJsonError("参数和结果映射必须是 JSON 对象");
    }
  };

  if (panel) {
    if (spec.type !== "agent") {
      return (
        <WorkflowNodePanelForm
          spec={spec}
          draft={draft}
          set={set}
          toolOptions={toolOptions}
          argumentsJson={argumentsJson}
          assignmentsJson={assignmentsJson}
          jsonError={jsonError}
          setArgumentsJson={setArgumentsJson}
          setAssignmentsJson={setAssignmentsJson}
          commitActionJson={commitActionJson}
        />
      );
    }
    return (
      <AgentNodePanel
        draft={draft}
        set={set}
        setPatch={setPatch}
        workflowSettings={workflowSettings}
        toolOptions={toolOptions}
        knowledgeOptions={knowledgeOptions}
        llmOptions={llmOptions}
        asrOptions={asrOptions}
        ttsOptions={ttsOptions}
        visionOptions={visionOptions}
      />
    );
  }

  return (
    <>
      {!panel && (
        <DialogHeader>
          <DialogTitle className="font-display text-ink">
            编辑{spec.displayName}
          </DialogTitle>
        </DialogHeader>
      )}

      <div className="flex flex-col gap-5 py-2">
        {spec.fields.map((field) => {
          const raw = draft[field.key];
          if (field.type === "switch") {
            return (
              <label
                key={field.key}
                className="flex items-center justify-between gap-3"
              >
                <span className="text-sm font-medium text-foreground">
                  {field.label}
                </span>
                <Switch
                  checked={Boolean(raw)}
                  onCheckedChange={(checked) => set(field.key, checked)}
                />
              </label>
            );
          }
          return (
            <div key={field.key} className="flex flex-col gap-2">
              <label className="text-sm font-medium text-foreground">
                {field.label}
                {field.required && <span className="text-destructive"> *</span>}
              </label>
              {field.type === "textarea" ? (
                <Textarea
                  rows={4}
                  value={(raw as string) ?? ""}
                  onChange={(e) => set(field.key, e.target.value)}
                  className="field-sizing-fixed min-h-32 resize-y border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
                />
              ) : (
                <Input
                  value={(raw as string) ?? ""}
                  onChange={(e) => set(field.key, e.target.value)}
                  className="border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
                />
              )}
            </div>
          );
        })}

        {spec.type === "agent" && (
          <>
            <NodeSelect
              label="进入节点时"
              value={(draft.entryMode as string) || "wait_user"}
              options={[
                { value: "wait_user", label: "等待用户说话（默认）" },
                { value: "generate", label: "立即让 LLM 回复" },
                { value: "fixed_speech", label: "播放固定进入语" },
              ]}
              onChange={(value) => set("entryMode", value || "wait_user")}
              allowNone={false}
            />
            {draft.entryMode === "fixed_speech" && (
              <div className="block">
                <div className="mb-2 text-sm font-medium text-foreground">
                  固定进入语 <span className="text-destructive">*</span>
                </div>
                <Textarea
                  rows={3}
                  value={draft.entrySpeech ?? ""}
                  onChange={(event) => set("entrySpeech", event.target.value)}
                  placeholder="例如：您好，请告诉我需要处理的问题。"
                  className="field-sizing-fixed min-h-24 resize-y border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
                />
                <span className="mt-2 block text-xs text-muted-soft">
                  支持使用 {"{{variable}}"} 动态变量；只播放语音，不调用 LLM。
                </span>
              </div>
            )}
            <div className="flex flex-col gap-2">
              <label className="text-sm font-medium text-foreground">可用工具</label>
              <ToolOptionPicker
                options={toolOptions}
                selectedIds={draft.toolIds ?? []}
                onChange={(toolIds) => set("toolIds", toolIds)}
              />
            </div>
            <NodeSelect
              label="知识库"
              value={(draft.knowledgeBaseId as string) || ""}
              options={knowledgeOptions}
              onChange={(value) => set("knowledgeBaseId", value || "")}
            />
            <NodeSelect
              label="知识库模式"
              value={(draft.knowledgeMode as string) || "disabled"}
              options={[
                { value: "disabled", label: "关闭" },
                { value: "automatic", label: "每轮自动检索" },
                { value: "on_demand", label: "Agent 按需调用" },
              ]}
              onChange={(value) => set("knowledgeMode", value || "disabled")}
              allowNone={false}
            />
            <NodeSelect
              label="ASR 资源"
              value={(draft.asrResourceId as string) || ""}
              options={asrOptions}
              onChange={(value) => set("asrResourceId", value || "")}
              noneLabel="继承 Workflow 默认值"
            />
            <NodeSelect
              label="TTS 资源"
              value={(draft.ttsResourceId as string) || ""}
              options={ttsOptions}
              onChange={(value) => set("ttsResourceId", value || "")}
              noneLabel="继承 Workflow 默认值"
            />
          </>
        )}

        {spec.type === "action" && (
          <>
            <NodeSelect
              label="确定性执行工具"
              value={(draft.toolId as string) || ""}
              options={toolOptions}
              onChange={(value) => set("toolId", value || "")}
              noneLabel="请选择工具"
            />
            <div className="flex flex-col gap-2">
              <label className="text-sm font-medium text-foreground">工具参数 JSON</label>
              <Textarea
                rows={5}
                value={argumentsJson}
                onChange={(event) => {
                  const value = event.target.value;
                  setArgumentsJson(value);
                  commitActionJson(value, assignmentsJson);
                }}
                className="field-sizing-fixed min-h-32 resize-y border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
              />
              <span className="text-xs text-muted-soft">字符串值可使用 {"{{variable}}"} 动态变量。</span>
            </div>
            <div className="flex flex-col gap-2">
              <label className="text-sm font-medium text-foreground">结果变量映射 JSON</label>
              <Textarea
                rows={4}
                value={assignmentsJson}
                onChange={(event) => {
                  const value = event.target.value;
                  setAssignmentsJson(value);
                  commitActionJson(argumentsJson, value);
                }}
                className="field-sizing-fixed min-h-28 resize-y border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
              />
              <span className="text-xs text-muted-soft">格式：变量名 → 响应 JSON Path。</span>
            </div>
            {jsonError && <span className="text-xs text-destructive">{jsonError}</span>}
          </>
        )}

        {spec.type === "handoff" && (
          <NodeSelect
            label="转交类型"
            value={(draft.targetType as string) || "human"}
            options={[
              { value: "ai", label: "其他 AI" },
              { value: "human", label: "人工" },
              { value: "queue", label: "队列" },
              { value: "phone", label: "电话" },
            ]}
            onChange={(value) => set("targetType", value || "human")}
            allowNone={false}
          />
        )}

        {spec.type === "end" && (
          <NodeSelect
            label="结束范围"
            value={(draft.scope as string) || "session"}
            options={[
              { value: "flow", label: "仅结束 AI 流程" },
              { value: "session", label: "结束音视频会话" },
            ]}
            onChange={(value) => set("scope", value || "session")}
            allowNone={false}
          />
        )}
      </div>
    </>
  );
}

function WorkflowNodePanelForm({
  spec,
  draft,
  set,
  toolOptions,
  argumentsJson,
  assignmentsJson,
  jsonError,
  setArgumentsJson,
  setAssignmentsJson,
  commitActionJson,
}: {
  spec: RuntimeNodeSpec;
  draft: WorkflowNodeData;
  set: (key: string, val: unknown) => void;
  toolOptions: ModelOption[];
  argumentsJson: string;
  assignmentsJson: string;
  jsonError: string;
  setArgumentsJson: (value: string) => void;
  setAssignmentsJson: (value: string) => void;
  commitActionJson: (argumentsValue: string, assignmentsValue: string) => void;
}) {
  return (
    <div className="space-y-3">
      <SectionCard
        icon={<Tag size={15} />}
        title="节点信息"
        description="节点在画布上显示的名称"
      >
        <label className="block">
          <div className="mb-1.5 text-sm font-medium text-foreground">
            节点名称
          </div>
          <Input
            value={draft.name ?? ""}
            onChange={(event) => set("name", event.target.value)}
            className="border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
          />
        </label>
      </SectionCard>

      {spec.type === "start" && (
        <SectionCard
          icon={<Play size={15} />}
          title="开场白"
          description="会话建立后首先向用户播放的固定内容"
        >
          <label className="block">
            <div className="mb-1.5 text-sm font-medium text-foreground">
              固定开场白
            </div>
            <Textarea
              rows={5}
              value={draft.greeting ?? ""}
              onChange={(event) => set("greeting", event.target.value)}
              placeholder="例如：你好，我是 AI 视频助手，有什么可以帮你？"
              className="field-sizing-fixed min-h-28 resize-y border-hairline-strong bg-background text-sm text-foreground placeholder:text-muted-soft"
            />
          </label>
        </SectionCard>
      )}

      {spec.type === "action" && (
        <ActionNodePanel
          draft={draft}
          set={set}
          toolOptions={toolOptions}
          argumentsJson={argumentsJson}
          assignmentsJson={assignmentsJson}
          jsonError={jsonError}
          setArgumentsJson={setArgumentsJson}
          setAssignmentsJson={setAssignmentsJson}
          commitActionJson={commitActionJson}
        />
      )}

      {spec.type === "handoff" && (
        <SectionCard
          icon={<PhoneForwarded size={15} />}
          title="转交配置"
          description="发送转交事件并继续执行工作流"
        >
          <NodeSelect
            label="转交类型"
            value={(draft.targetType as string) || "human"}
            options={[
              { value: "ai", label: "其他 AI" },
              { value: "human", label: "人工" },
              { value: "queue", label: "队列" },
              { value: "phone", label: "电话" },
            ]}
            onChange={(value) => set("targetType", value || "human")}
            allowNone={false}
          />
          <label className="block">
            <div className="mb-1.5 text-sm font-medium text-foreground">
              转交目标
            </div>
            <Input
              value={draft.target ?? ""}
              onChange={(event) => set("target", event.target.value)}
              placeholder="人工、队列、AI 或电话号码"
              className="border-hairline-strong bg-background text-foreground placeholder:text-muted-soft"
            />
          </label>
          <label className="block">
            <div className="mb-1.5 text-sm font-medium text-foreground">
              转交提示
            </div>
            <Textarea
              rows={4}
              value={draft.message ?? ""}
              onChange={(event) => set("message", event.target.value)}
              placeholder="例如：好的，正在为你转接人工客服。"
              className="field-sizing-fixed min-h-24 resize-y border-hairline-strong bg-background text-sm text-foreground placeholder:text-muted-soft"
            />
          </label>
        </SectionCard>
      )}

      {spec.type === "end" && (
        <SectionCard
          icon={<Flag size={15} />}
          title="结束配置"
          description="结束工作流，并可在结束前播放一段固定回复"
        >
          <NodeSelect
            label="结束范围"
            value={(draft.scope as string) || "session"}
            options={[
              { value: "flow", label: "仅结束 AI 流程" },
              { value: "session", label: "结束音视频会话" },
            ]}
            onChange={(value) => set("scope", value || "session")}
            allowNone={false}
          />
          <label className="block">
            <div className="mb-1.5 text-sm font-medium text-foreground">
              固定结束语
            </div>
            <Textarea
              rows={4}
              value={draft.message ?? ""}
              onChange={(event) => set("message", event.target.value)}
              placeholder="例如：感谢你的来电，再见。"
              className="field-sizing-fixed min-h-24 resize-y border-hairline-strong bg-background text-sm text-foreground placeholder:text-muted-soft"
            />
          </label>
        </SectionCard>
      )}
    </div>
  );
}

/** Agent 右栏：与 AssistantPage 共用紧凑 SectionCard。 */
