"use client";

/**
 * 스크립트 실행 노드 속성 편집
 */

import { useEffect, useState, useCallback } from "react";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Switch } from "@/components/ui/switch";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Plus, Trash2, Terminal, FileCode, Settings, Play } from "lucide-react";
import { useFlowEditorStore } from "@/lib/stores/flowEditorStore";
import type { ScriptActionNodeData } from "@/types/node-editor";

interface ScriptActionPropertiesProps {
  nodeId: string;
  data: ScriptActionNodeData;
}

export function ScriptActionProperties({ nodeId, data }: ScriptActionPropertiesProps) {
  const { updateNode } = useFlowEditorStore();

  // 로컬 상태
  const [displayName, setDisplayName] = useState(data.displayName || "스크립트 실행");
  const [scriptType, setScriptType] = useState<ScriptActionNodeData["scriptType"]>(data.scriptType || "python");
  const [executionMode, setExecutionMode] = useState<"inline" | "file">(data.executionMode || "inline");
  const [inlineScript, setInlineScript] = useState(data.inlineScript || "");
  const [scriptPath, setScriptPath] = useState(data.scriptPath || "");
  const [executablePath, setExecutablePath] = useState(data.executablePath || "");
  const [inputMethod, setInputMethod] = useState<ScriptActionNodeData["inputMethod"]>(data.inputMethod || "stdin");
  const [inputFormat, setInputFormat] = useState<"json" | "csv" | "text">(data.inputFormat || "json");
  const [workingDirectory, setWorkingDirectory] = useState(data.workingDirectory || "");
  const [timeout, setTimeout] = useState(data.options?.timeout?.toString() || "60000");
  const [maxBuffer, setMaxBuffer] = useState(data.options?.maxBuffer?.toString() || "1048576");
  const [shell, setShell] = useState(data.options?.shell || "");
  const [captureStdout, setCaptureStdout] = useState(data.outputHandling?.captureStdout ?? true);
  const [captureStderr, setCaptureStderr] = useState(data.outputHandling?.captureStderr ?? true);
  const [parseOutput, setParseOutput] = useState<"json" | "lines" | "text">(data.outputHandling?.parseOutput || "text");
  
  // 환경변수
  const [envVars, setEnvVars] = useState<Array<{ key: string; value: string }>>(
    Object.entries(data.environmentVariables || {}).map(([key, value]) => ({ key, value }))
  );
  
  // 명령줄 인자
  const [args, setArgs] = useState<string[]>(data.arguments || []);

  // 데이터 변경 시 로컬 상태 동기화
  useEffect(() => {
    setDisplayName(data.displayName || "스크립트 실행");
    setScriptType(data.scriptType || "python");
    setExecutionMode(data.executionMode || "inline");
    setInlineScript(data.inlineScript || "");
    setScriptPath(data.scriptPath || "");
    setExecutablePath(data.executablePath || "");
    setInputMethod(data.inputMethod || "stdin");
    setInputFormat(data.inputFormat || "json");
    setWorkingDirectory(data.workingDirectory || "");
    setTimeout(data.options?.timeout?.toString() || "60000");
    setMaxBuffer(data.options?.maxBuffer?.toString() || "1048576");
    setShell(data.options?.shell || "");
    setCaptureStdout(data.outputHandling?.captureStdout ?? true);
    setCaptureStderr(data.outputHandling?.captureStderr ?? true);
    setParseOutput(data.outputHandling?.parseOutput || "text");
    setEnvVars(Object.entries(data.environmentVariables || {}).map(([key, value]) => ({ key, value })));
    setArgs(data.arguments || []);
  }, [data]);

  // 노드 업데이트 함수
  const updateNodeData = useCallback(
    (updates: Partial<ScriptActionNodeData>) => {
      updateNode(nodeId, {
        ...data,
        ...updates,
      });
    },
    [nodeId, data, updateNode]
  );

  // 표시명 변경
  const handleDisplayNameChange = (value: string) => {
    setDisplayName(value);
    updateNodeData({ displayName: value });
  };

  // 스크립트 타입 변경
  const handleScriptTypeChange = (value: ScriptActionNodeData["scriptType"]) => {
    setScriptType(value);
    updateNodeData({ scriptType: value });
  };

  // 실행 모드 변경
  const handleExecutionModeChange = (value: "inline" | "file") => {
    setExecutionMode(value);
    updateNodeData({ executionMode: value });
  };

  // 스크립트 내용 업데이트
  const updateScriptContent = useCallback(() => {
    updateNodeData({
      inlineScript,
      scriptPath,
      executablePath,
    });
  }, [inlineScript, scriptPath, executablePath, updateNodeData]);

  // 입력 설정 업데이트
  const updateInputSettings = useCallback(() => {
    updateNodeData({
      inputMethod,
      inputFormat,
      workingDirectory: workingDirectory || undefined,
    });
  }, [inputMethod, inputFormat, workingDirectory, updateNodeData]);

  // 옵션 업데이트
  const updateOptions = useCallback(() => {
    updateNodeData({
      options: {
        timeout: parseInt(timeout) || 60000,
        maxBuffer: parseInt(maxBuffer) || 1048576,
        shell: shell || undefined,
      },
    });
  }, [timeout, maxBuffer, shell, updateNodeData]);

  // 출력 처리 업데이트
  const updateOutputHandling = useCallback(() => {
    updateNodeData({
      outputHandling: {
        captureStdout,
        captureStderr,
        parseOutput,
      },
    });
  }, [captureStdout, captureStderr, parseOutput, updateNodeData]);

  // 환경변수 추가
  const addEnvVar = () => {
    const newEnvVars = [...envVars, { key: "", value: "" }];
    setEnvVars(newEnvVars);
  };

  // 환경변수 삭제
  const removeEnvVar = (index: number) => {
    const newEnvVars = envVars.filter((_, i) => i !== index);
    setEnvVars(newEnvVars);
    const envObj = Object.fromEntries(newEnvVars.filter(e => e.key).map(e => [e.key, e.value]));
    updateNodeData({ environmentVariables: envObj });
  };

  // 환경변수 업데이트
  const updateEnvVar = (index: number, field: "key" | "value", value: string) => {
    const newEnvVars = [...envVars];
    newEnvVars[index][field] = value;
    setEnvVars(newEnvVars);
  };

  // 환경변수 저장
  const saveEnvVars = () => {
    const envObj = Object.fromEntries(envVars.filter(e => e.key).map(e => [e.key, e.value]));
    updateNodeData({ environmentVariables: envObj });
  };

  // 인자 추가
  const addArg = () => {
    const newArgs = [...args, ""];
    setArgs(newArgs);
  };

  // 인자 삭제
  const removeArg = (index: number) => {
    const newArgs = args.filter((_, i) => i !== index);
    setArgs(newArgs);
    updateNodeData({ arguments: newArgs });
  };

  // 인자 업데이트
  const updateArg = (index: number, value: string) => {
    const newArgs = [...args];
    newArgs[index] = value;
    setArgs(newArgs);
  };

  // 인자 저장
  const saveArgs = () => {
    updateNodeData({ arguments: args.filter(a => a) });
  };

  // 스크립트 타입별 기본 스크립트 템플릿
  const getScriptTemplate = (type: string) => {
    switch (type) {
      case "python":
        return `import sys
import json

# 입력 데이터 읽기 (stdin)
input_data = json.loads(sys.stdin.read())

# 처리 로직
result = {
    "status": "success",
    "data": input_data
}

# 결과 출력
print(json.dumps(result))`;
      case "shell":
        return `#!/bin/bash

# 입력 데이터 읽기
INPUT=$(cat)

# 처리 로직
echo "입력 데이터: $INPUT"

# 결과 출력
echo '{"status": "success"}'`;
      case "powershell":
        return `# 입력 데이터 읽기
$input = $input | ConvertFrom-Json

# 처리 로직
$result = @{
    status = "success"
    data = $input
}

# 결과 출력
$result | ConvertTo-Json`;
      case "node":
        return `const readline = require('readline');

let input = '';

process.stdin.on('data', (chunk) => {
  input += chunk;
});

process.stdin.on('end', () => {
  const data = JSON.parse(input);
  
  // 처리 로직
  const result = {
    status: 'success',
    data: data
  };
  
  console.log(JSON.stringify(result));
});`;
      default:
        return "";
    }
  };

  return (
    <div className="space-y-4 p-4">
      {/* 표시명 */}
      <div className="space-y-2">
        <Label className="text-xs font-medium">표시명</Label>
        <Input
          value={displayName}
          onChange={(e) => handleDisplayNameChange(e.target.value)}
          placeholder="스크립트 실행"
          className="h-8 text-sm"
        />
      </div>

      {/* 스크립트 타입 */}
      <div className="space-y-2">
        <Label className="text-xs font-medium">스크립트 타입</Label>
        <Select value={scriptType} onValueChange={handleScriptTypeChange}>
          <SelectTrigger className="h-8 text-sm">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="python">Python</SelectItem>
            <SelectItem value="shell">Shell (Bash)</SelectItem>
            <SelectItem value="powershell">PowerShell</SelectItem>
            <SelectItem value="node">Node.js</SelectItem>
            <SelectItem value="executable">실행 파일</SelectItem>
          </SelectContent>
        </Select>
      </div>

      {/* 실행 모드 */}
      <div className="space-y-2">
        <Label className="text-xs font-medium">실행 방식</Label>
        <Select value={executionMode} onValueChange={handleExecutionModeChange}>
          <SelectTrigger className="h-8 text-sm">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="inline">인라인 스크립트</SelectItem>
            <SelectItem value="file">파일 실행</SelectItem>
          </SelectContent>
        </Select>
      </div>

      <Tabs defaultValue="script" className="w-full">
        <TabsList className="grid w-full grid-cols-4">
          <TabsTrigger value="script" className="text-xs">
            <FileCode className="mr-1 h-3 w-3" />
            스크립트
          </TabsTrigger>
          <TabsTrigger value="input" className="text-xs">
            <Play className="mr-1 h-3 w-3" />
            입력
          </TabsTrigger>
          <TabsTrigger value="env" className="text-xs">
            <Terminal className="mr-1 h-3 w-3" />
            환경
          </TabsTrigger>
          <TabsTrigger value="output" className="text-xs">
            <Settings className="mr-1 h-3 w-3" />
            출력
          </TabsTrigger>
        </TabsList>

        {/* 스크립트 탭 */}
        <TabsContent value="script" className="space-y-3 pt-3">
          {executionMode === "inline" ? (
            <div className="space-y-2">
              <div className="flex items-center justify-between">
                <Label className="text-xs">스크립트 코드</Label>
                <Button
                  variant="outline"
                  size="sm"
                  className="h-6 text-xs"
                  onClick={() => setInlineScript(getScriptTemplate(scriptType))}
                >
                  템플릿 삽입
                </Button>
              </div>
              <Textarea
                value={inlineScript}
                onChange={(e) => setInlineScript(e.target.value)}
                onBlur={updateScriptContent}
                placeholder="스크립트 코드를 입력하세요..."
                className="min-h-[250px] font-mono text-xs"
              />
            </div>
          ) : (
            <div className="space-y-3">
              {scriptType === "executable" ? (
                <div className="space-y-2">
                  <Label className="text-xs">실행 파일 경로</Label>
                  <Input
                    value={executablePath}
                    onChange={(e) => setExecutablePath(e.target.value)}
                    onBlur={updateScriptContent}
                    placeholder="/path/to/executable"
                    className="h-8 text-sm"
                  />
                </div>
              ) : (
                <div className="space-y-2">
                  <Label className="text-xs">스크립트 파일 경로</Label>
                  <Input
                    value={scriptPath}
                    onChange={(e) => setScriptPath(e.target.value)}
                    onBlur={updateScriptContent}
                    placeholder={`/path/to/script.${scriptType === "python" ? "py" : scriptType === "shell" ? "sh" : scriptType === "powershell" ? "ps1" : "js"}`}
                    className="h-8 text-sm"
                  />
                </div>
              )}
            </div>
          )}

          {/* 명령줄 인자 */}
          <div className="space-y-2">
            <div className="flex items-center justify-between">
              <Label className="text-xs">명령줄 인자</Label>
              <Button variant="outline" size="sm" className="h-6 text-xs" onClick={addArg}>
                <Plus className="mr-1 h-3 w-3" />
                추가
              </Button>
            </div>
            {args.map((arg, index) => (
              <div key={index} className="flex gap-2">
                <Input
                  value={arg}
                  onChange={(e) => updateArg(index, e.target.value)}
                  onBlur={saveArgs}
                  placeholder={`인자 ${index + 1}`}
                  className="h-8 text-sm"
                />
                <Button variant="ghost" size="sm" className="h-8 w-8 p-0" onClick={() => removeArg(index)}>
                  <Trash2 className="h-3 w-3 text-red-500" />
                </Button>
              </div>
            ))}
          </div>
        </TabsContent>

        {/* 입력 탭 */}
        <TabsContent value="input" className="space-y-3 pt-3">
          <div className="space-y-2">
            <Label className="text-xs">입력 전달 방식</Label>
            <Select value={inputMethod} onValueChange={(v: ScriptActionNodeData["inputMethod"]) => {
              setInputMethod(v);
              updateNodeData({ inputMethod: v });
            }}>
              <SelectTrigger className="h-8 text-sm">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="stdin">표준입력 (stdin)</SelectItem>
                <SelectItem value="args">명령줄 인자</SelectItem>
                <SelectItem value="env">환경변수</SelectItem>
                <SelectItem value="file">임시 파일</SelectItem>
              </SelectContent>
            </Select>
          </div>

          {(inputMethod === "stdin" || inputMethod === "file") && (
            <div className="space-y-2">
              <Label className="text-xs">입력 형식</Label>
              <Select value={inputFormat} onValueChange={(v: "json" | "csv" | "text") => {
                setInputFormat(v);
                updateNodeData({ inputFormat: v });
              }}>
                <SelectTrigger className="h-8 text-sm">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="json">JSON</SelectItem>
                  <SelectItem value="csv">CSV</SelectItem>
                  <SelectItem value="text">텍스트</SelectItem>
                </SelectContent>
              </Select>
            </div>
          )}

          <div className="space-y-2">
            <Label className="text-xs">작업 디렉토리</Label>
            <Input
              value={workingDirectory}
              onChange={(e) => setWorkingDirectory(e.target.value)}
              onBlur={updateInputSettings}
              placeholder="/path/to/working/directory"
              className="h-8 text-sm"
            />
          </div>

          <div className="space-y-2">
            <Label className="text-xs">타임아웃 (ms)</Label>
            <Input
              type="number"
              value={timeout}
              onChange={(e) => setTimeout(e.target.value)}
              onBlur={updateOptions}
              placeholder="60000"
              className="h-8 text-sm"
            />
          </div>
        </TabsContent>

        {/* 환경변수 탭 */}
        <TabsContent value="env" className="space-y-3 pt-3">
          <div className="flex items-center justify-between">
            <Label className="text-xs">환경변수</Label>
            <Button variant="outline" size="sm" className="h-6 text-xs" onClick={addEnvVar}>
              <Plus className="mr-1 h-3 w-3" />
              추가
            </Button>
          </div>

          {envVars.map((env, index) => (
            <div key={index} className="flex gap-2">
              <Input
                value={env.key}
                onChange={(e) => updateEnvVar(index, "key", e.target.value)}
                onBlur={saveEnvVars}
                placeholder="변수명"
                className="h-8 text-sm"
              />
              <Input
                value={env.value}
                onChange={(e) => updateEnvVar(index, "value", e.target.value)}
                onBlur={saveEnvVars}
                placeholder="값"
                className="h-8 text-sm"
              />
              <Button variant="ghost" size="sm" className="h-8 w-8 p-0" onClick={() => removeEnvVar(index)}>
                <Trash2 className="h-3 w-3 text-red-500" />
              </Button>
            </div>
          ))}

          {envVars.length === 0 && (
            <Card className="bg-gray-50">
              <CardContent className="p-3 text-xs text-gray-500">
                환경변수가 없습니다. 추가 버튼을 클릭하여 환경변수를 설정하세요.
              </CardContent>
            </Card>
          )}

          <div className="space-y-2">
            <Label className="text-xs">사용할 쉘</Label>
            <Input
              value={shell}
              onChange={(e) => setShell(e.target.value)}
              onBlur={updateOptions}
              placeholder="/bin/bash (기본값 사용 시 비워두기)"
              className="h-8 text-sm"
            />
          </div>
        </TabsContent>

        {/* 출력 탭 */}
        <TabsContent value="output" className="space-y-3 pt-3">
          <div className="flex items-center space-x-2">
            <Switch
              checked={captureStdout}
              onCheckedChange={(checked) => {
                setCaptureStdout(checked);
                updateNodeData({
                  outputHandling: { ...data.outputHandling, captureStdout: checked, captureStderr, parseOutput },
                });
              }}
            />
            <Label className="text-xs">표준출력 (stdout) 캡처</Label>
          </div>

          <div className="flex items-center space-x-2">
            <Switch
              checked={captureStderr}
              onCheckedChange={(checked) => {
                setCaptureStderr(checked);
                updateNodeData({
                  outputHandling: { ...data.outputHandling, captureStdout, captureStderr: checked, parseOutput },
                });
              }}
            />
            <Label className="text-xs">표준에러 (stderr) 캡처</Label>
          </div>

          <div className="space-y-2">
            <Label className="text-xs">출력 파싱</Label>
            <Select value={parseOutput} onValueChange={(v: "json" | "lines" | "text") => {
              setParseOutput(v);
              updateNodeData({
                outputHandling: { ...data.outputHandling, captureStdout, captureStderr, parseOutput: v },
              });
            }}>
              <SelectTrigger className="h-8 text-sm">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="json">JSON 파싱</SelectItem>
                <SelectItem value="lines">줄 단위 배열</SelectItem>
                <SelectItem value="text">텍스트 그대로</SelectItem>
              </SelectContent>
            </Select>
          </div>

          <Card className="bg-gray-50">
            <CardContent className="p-3 text-xs text-gray-600">
              <div className="font-medium mb-1">출력 데이터 사용:</div>
              스크립트의 출력은 다음 노드에서 <code>{"{{scriptOutput}}"}</code>로 참조할 수 있습니다.
            </CardContent>
          </Card>
        </TabsContent>
      </Tabs>
    </div>
  );
}

