// File: frontend/app/workflow/components/LLMNode.tsx
// Description: 自定义 LLM 节点组件

import React, {
  useState,
  useCallback,
  useEffect,
  memo,
  ChangeEvent,
} from "react";
import {
  Handle,
  Position,
  useUpdateNodeInternals,
  useReactFlow,
  Node,
} from "reactflow";
import { BrainCircuit } from "lucide-react";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Slider } from "@/components/ui/slider";
import { Label } from "@/components/ui/label";
import {
  type LLMNodeData,
  type CustomNodeProps,
  availableModels,
} from "./types"; // 导入类型和模型列表

const LLMNodeComponent = ({
  id,
  data,
  isConnectable,
}: CustomNodeProps<LLMNodeData>) => {
  //   const [currentData, setCurrentData] = useState<LLMNodeData>(data);
  const updateNodeInternals = useUpdateNodeInternals();
  const { setNodes } = useReactFlow<LLMNodeData>(); // 获取 setNodes 方法

  // 处理内部表单变化的通用回调 - 直接更新 React Flow 主状态
  const handleDataChange = useCallback(
    (key: keyof LLMNodeData, value: any) => {
      // 使用 setNodes 更新特定节点的数据
      setNodes(
        (
          nds: Node<LLMNodeData>[] // 显式指定类型
        ) =>
          nds.map((node) => {
            if (node.id === id) {
              // 创建一个新的 data 对象
              const updatedData = { ...node.data, [key]: value };
              return { ...node, data: updatedData };
            }
            return node;
          })
      );
      console.log(`(LLMNode) Node ${id} data updated:`, { [key]: value });
    },
    [id, setNodes]
  ); // 依赖 id 和 setNodes

  const handleSliderChange = useCallback(
    (value: number[]) => {
      handleDataChange("temperature", value[0]);
    },
    [handleDataChange]
  );
  const handleSelectChange = useCallback(
    (value: string) => {
      handleDataChange("model", value);
    },
    [handleDataChange]
  );
  const handleTextChange = useCallback(
    (event: ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
      const { name, value } = event.target;
      handleDataChange(name as keyof LLMNodeData, value);
    },
    [handleDataChange]
  );

  // 检查 inputConnected 状态是否需要更新 (如果外部更新了)
  // 注意：这个逻辑依赖于父组件正确更新了 data.inputConnected
  useEffect(() => {
    // 可以在这里添加逻辑，如果 props.data.inputConnected 和 UI 显示不一致时触发更新
    // 但通常连接状态由 onConnect/onEdgesChange 在父组件处理更佳
    // updateNodeInternals(id); // 如果 Handle 显示依赖 inputConnected，可能需要调用
  }, [data.inputConnected, id, updateNodeInternals]);

  return (
    // 调整宽度，例如 w-96 (24rem)
    <div className="react-flow__node-genericNode nopan bg-purple-50 dark:bg-gray-800 border border-purple-200 dark:border-gray-700 rounded-lg shadow-lg w-96">
      <div className="bg-purple-100 dark:bg-gray-700 p-3 border-b border-purple-200 dark:border-gray-600">
        <div className="flex items-center gap-2">
          <BrainCircuit
            size={18}
            className="text-purple-700 dark:text-purple-300"
          />
          <strong className="text-purple-800 dark:text-purple-200">
            LLM 调用
          </strong>
        </div>
        <p className="text-xs text-purple-600 dark:text-purple-400 mt-1">
          使用大语言模型生成文本
        </p>
      </div>
      <div className="p-4 space-y-3">
        <div className="relative nodrag">
          <Handle
            type="target"
            position={Position.Left}
            id="input-text"
            isConnectable={isConnectable}
            className="!w-3 !h-3 !bg-blue-500 top-1/2 z-50 !-left-5"
          />
          <Label className="text-xs font-semibold text-gray-500 dark:text-gray-400">
            输入
          </Label>
          {/* 直接使用 props.data.inputConnected */}
          {!data.inputConnected && (
            <p className="text-xs text-gray-400 italic mt-1">连接文本或提示</p>
          )}
        </div>
        <div className="nodrag">
          <Label
            htmlFor={`systemPrompt-${id}`}
            className="text-xs font-semibold"
          >
            系统提示
          </Label>
          {/* 直接使用 props.data 和 onChange 回调 */}
          <Textarea
            id={`systemPrompt-${id}`}
            name="systemPrompt"
            value={data.systemPrompt}
            onChange={handleTextChange}
            placeholder="例如：你是一个乐于助人的助手。"
            className="mt-1 text-xs min-h-[60px] bg-white dark:bg-gray-700"
            rows={3}
          />
        </div>
        <div className="nodrag">
          <Label htmlFor={`model-${id}`} className="text-xs font-semibold">
            模型名称
          </Label>
          <Select
            name="model"
            value={data.model}
            onValueChange={handleSelectChange}
          >
            <SelectTrigger
              id={`model-${id}`}
              className="mt-1 h-8 text-xs bg-white dark:bg-gray-700"
            >
              <SelectValue placeholder="选择模型" />
            </SelectTrigger>
            <SelectContent>
              {availableModels.map((model) => (
                <SelectItem
                  key={model.value}
                  value={model.value}
                  className="text-xs"
                >
                  {model.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
        <div className="nodrag">
          <Label htmlFor={`apiKey-${id}`} className="text-xs font-semibold">
            API Key (不安全)
          </Label>
          <Input
            id={`apiKey-${id}`}
            name="apiKey"
            type="password"
            value={data.apiKey || ""}
            onChange={handleTextChange}
            placeholder="sk-..."
            className="mt-1 h-8 text-xs bg-white dark:bg-gray-700"
          />
          <p className="text-xs text-red-500 mt-1">
            警告：不建议在此处输入密钥。
          </p>
        </div>
        <div className="nodrag">
          <Label
            htmlFor={`temperature-${id}`}
            className="text-xs font-semibold"
          >
            温度: {data.temperature?.toFixed(1) ?? "N/A"}
          </Label>
          <Slider
            id={`temperature-${id}`}
            min={0}
            max={1}
            step={0.1}
            value={[data.temperature ?? 0.7]}
            onValueChange={handleSliderChange}
            className="mt-2"
          />
          <div className="flex justify-between text-xs text-gray-500 dark:text-gray-400 mt-1">
            <span>精确</span>
            <span>创造性</span>
          </div>
        </div>
      </div>
      <div className="relative p-2 border-t border-purple-200 dark:border-gray-600">
        <Label className="text-xs font-semibold text-gray-500 dark:text-gray-400 block text-right pr-6">
          输出
        </Label>
        <Handle
          type="source"
          position={Position.Right}
          id="output-message"
          isConnectable={isConnectable}
          className="!w-3 !h-3 !bg-green-500 top-1/2 z-50"
        />
      </div>
    </div>
  );
};

LLMNodeComponent.displayName = "LLMNode";
export const LLMNode = memo(LLMNodeComponent);
