"use client";

import { useState, useEffect, useMemo } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Plus, Trash2, Play, AlertCircle, Database, Link2 } from "lucide-react";
import { useReportDesigner, ReportQuery } from "@/contexts/ReportDesignerContext";
import { Badge } from "@/components/ui/badge";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { reportApi } from "@/lib/api/reportApi";
import { useToast } from "@/hooks/use-toast";
import type { ExternalConnection } from "@/types/report";
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";

// SQL 쿼리 안전성 검증 함수 (컴포넌트 외부에 선언)
const validateQuerySafety = (sql: string): { isValid: boolean; errorMessage: string | null } => {
  if (!sql || sql.trim() === "") {
    return { isValid: false, errorMessage: "쿼리를 입력해주세요." };
  }

  // 위험한 SQL 명령어 목록
  const dangerousKeywords = [
    "DELETE",
    "DROP",
    "TRUNCATE",
    "INSERT",
    "UPDATE",
    "ALTER",
    "CREATE",
    "REPLACE",
    "MERGE",
    "GRANT",
    "REVOKE",
    "EXECUTE",
    "EXEC",
    "CALL",
  ];

  // SQL을 대문자로 변환하여 검사
  const upperSql = sql.toUpperCase().trim();

  // 위험한 키워드 검사
  for (const keyword of dangerousKeywords) {
    // 단어 경계를 고려하여 검사
    const regex = new RegExp(`\\b${keyword}\\b`, "i");
    if (regex.test(upperSql)) {
      return {
        isValid: false,
        errorMessage: `보안상의 이유로 ${keyword} 명령어는 사용할 수 없습니다. SELECT 쿼리만 허용됩니다.`,
      };
    }
  }

  // SELECT 쿼리인지 확인
  if (!upperSql.startsWith("SELECT") && !upperSql.startsWith("WITH")) {
    return {
      isValid: false,
      errorMessage: "SELECT 쿼리만 허용됩니다. 데이터 조회 용도로만 사용할 수 있습니다.",
    };
  }

  // 세미콜론으로 구분된 여러 쿼리 방지
  const semicolonCount = (sql.match(/;/g) || []).length;
  if (semicolonCount > 1 || (semicolonCount === 1 && !sql.trim().endsWith(";"))) {
    return {
      isValid: false,
      errorMessage: "보안상의 이유로 여러 개의 쿼리를 동시에 실행할 수 없습니다.",
    };
  }

  return { isValid: true, errorMessage: null };
};

export function QueryManager() {
  const { queries, setQueries, reportId, setQueryResult, getQueryResult } = useReportDesigner();
  const [isTestRunning, setIsTestRunning] = useState<Record<string, boolean>>({});
  const [parameterValues, setParameterValues] = useState<Record<string, Record<string, string>>>({});
  const [parameterTypes, setParameterTypes] = useState<Record<string, Record<string, string>>>({});
  const [externalConnections, setExternalConnections] = useState<ExternalConnection[]>([]);
  const [isLoadingConnections, setIsLoadingConnections] = useState(false);
  const { toast } = useToast();

  // 각 쿼리의 안전성 검증 결과
  const getQueryValidation = (query: ReportQuery) => validateQuerySafety(query.sqlQuery);

  // 외부 DB 연결 목록 조회
  useEffect(() => {
    const fetchConnections = async () => {
      setIsLoadingConnections(true);
      try {
        const response = await reportApi.getExternalConnections();
        if (response.success && response.data) {
          setExternalConnections(response.data);
        }
      } catch (error) {
        console.error("외부 DB 연결 목록 조회 실패:", error);
      } finally {
        setIsLoadingConnections(false);
      }
    };

    fetchConnections();
  }, []);

  // 파라미터 감지 ($1, $2 등, 단 작은따옴표 안은 제외)
  const detectParameters = (sql: string): string[] => {
    // 작은따옴표 안의 내용을 제거
    const withoutStrings = sql.replace(/'[^']*'/g, "");

    // $숫자 패턴 찾기
    const matches = withoutStrings.match(/\$\d+/g);
    if (!matches) return [];

    // 중복 제거하되 등장 순서 유지
    const seen = new Set<string>();
    const result: string[] = [];
    for (const match of matches) {
      if (!seen.has(match)) {
        seen.add(match);
        result.push(match);
      }
    }
    return result;
  };

  // 새 쿼리 추가
  const handleAddQuery = () => {
    const newQuery: ReportQuery = {
      id: `query_${Date.now()}`,
      name: `쿼리 ${queries.length + 1}`,
      type: "MASTER",
      sqlQuery: "",
      parameters: [],
      externalConnectionId: null,
    };
    setQueries([...queries, newQuery]);
  };

  // 쿼리 삭제
  const handleDeleteQuery = (queryId: string, e: React.MouseEvent) => {
    e.stopPropagation();
    setQueries(queries.filter((q) => q.id !== queryId));
    // 해당 쿼리의 상태 정리
    const newParameterValues = { ...parameterValues };
    const newParameterTypes = { ...parameterTypes };
    const newIsTestRunning = { ...isTestRunning };
    delete newParameterValues[queryId];
    delete newParameterTypes[queryId];
    delete newIsTestRunning[queryId];
    setParameterValues(newParameterValues);
    setParameterTypes(newParameterTypes);
    setIsTestRunning(newIsTestRunning);
  };

  // 파라미터 값이 모두 입력되었는지 확인
  const isAllParametersFilled = (query: ReportQuery): boolean => {
    if (!query || query.parameters.length === 0) {
      return true;
    }
    const queryParams = parameterValues[query.id] || {};
    return query.parameters.every((param) => {
      const value = queryParams[param];
      return value !== undefined && value.trim() !== "";
    });
  };

  // 쿼리 업데이트
  const handleUpdateQuery = (queryId: string, updates: Partial<ReportQuery>) => {
    setQueries(
      queries.map((q) => {
        if (q.id === queryId) {
          const updated = { ...q, ...updates };
          // SQL이 변경되면 파라미터 재감지
          if (updates.sqlQuery !== undefined) {
            updated.parameters = detectParameters(updated.sqlQuery);
          }
          return updated;
        }
        return q;
      }),
    );
  };

  // 쿼리 테스트 실행
  const handleTestQuery = async (query: ReportQuery) => {
    // SQL 쿼리 안전성 검증
    const validation = validateQuerySafety(query.sqlQuery);
    if (!validation.isValid) {
      toast({
        title: "쿼리 검증 실패",
        description: validation.errorMessage || "잘못된 쿼리입니다.",
        variant: "destructive",
      });
      return;
    }

    setIsTestRunning({ ...isTestRunning, [query.id]: true });
    try {
      const testReportId = reportId === "new" ? "TEMP_TEST" : reportId;
      // 항상 sqlQuery를 전달 (새 쿼리가 아직 DB에 저장되지 않았을 수 있음)
      const sqlQuery = query.sqlQuery;
      const externalConnectionId = (query as any).externalConnectionId || null;
      const queryParams = parameterValues[query.id] || {};

      const response = await reportApi.executeQuery(
        testReportId,
        query.id,
        queryParams,
        sqlQuery,
        externalConnectionId,
      );

      if (response.success && response.data) {
        setQueryResult(query.id, response.data.fields, response.data.rows);

        toast({
          title: "성공",
          description: `${response.data.rows.length}건의 데이터가 조회되었습니다.`,
        });
      }
    } catch (error: any) {
      toast({
        title: "오류",
        description: error.response?.data?.message || "쿼리 실행에 실패했습니다.",
        variant: "destructive",
      });
    } finally {
      setIsTestRunning({ ...isTestRunning, [query.id]: false });
    }
  };

  return (
    <ScrollArea className="h-full">
      <div className="space-y-4 p-4">
        {/* 헤더 */}
        <div className="flex items-center justify-between">
          <h3 className="text-sm font-semibold">쿼리 관리</h3>
          <Button size="sm" onClick={handleAddQuery}>
            <Plus className="mr-1 h-4 w-4" />
            추가
          </Button>
        </div>

        {/* 안내 메시지 */}
        <Alert>
          <AlertCircle className="h-4 w-4" />
          <AlertDescription className="text-xs">
            <strong>마스터 쿼리</strong>는 1건의 데이터를 가져오고,
            <strong>디테일 쿼리</strong>는 여러 건을 반복 표시합니다.
          </AlertDescription>
        </Alert>

        {/* 아코디언 목록 */}
        {queries.length > 0 ? (
          <Accordion type="single" collapsible>
            {queries.map((query) => {
              const testResult = getQueryResult(query.id);
              const queryValidation = getQueryValidation(query);
              const queryParams = parameterValues[query.id] || {};
              const queryParamTypes = parameterTypes[query.id] || {};

              return (
                <AccordionItem key={query.id} value={query.id} className="border-b border-border">
                  <div className="flex items-center gap-1">
                    <AccordionTrigger className="flex-1 px-0 py-2.5 hover:no-underline">
                      <div className="flex items-center gap-2">
                        <span className="text-sm font-medium">{query.name}</span>
                        <Badge variant={query.type === "MASTER" ? "default" : "secondary"} className="text-xs">
                          {query.type}
                        </Badge>
                      </div>
                    </AccordionTrigger>
                      <Button
                        variant="ghost"
                        size="sm"
                        onClick={(e) => handleDeleteQuery(query.id, e)}
                      className="h-7 w-7 shrink-0 p-0"
                      >
                        <Trash2 className="h-4 w-4 text-destructive" />
                      </Button>
                    </div>
                  <AccordionContent className="space-y-4 pt-1 pr-0 pb-3 pl-0">
                    {/* 쿼리 이름 */}
                    <div className="space-y-2">
                      <Label className="text-xs">쿼리 이름</Label>
                      <Input
                        value={query.name}
                        onChange={(e) => handleUpdateQuery(query.id, { name: e.target.value })}
                        placeholder="쿼리 이름"
                        className="h-8"
                      />
                    </div>

                    {/* 쿼리 타입 */}
                    <div className="space-y-2">
                      <Label className="text-xs">쿼리 타입</Label>
                      <Select
                        value={query.type}
                        onValueChange={(value: "MASTER" | "DETAIL") => handleUpdateQuery(query.id, { type: value })}
                      >
                        <SelectTrigger className="h-8">
                          <SelectValue />
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="MASTER">마스터 (1건)</SelectItem>
                          <SelectItem value="DETAIL">디테일 (반복)</SelectItem>
                        </SelectContent>
                      </Select>
                    </div>

                    {/* DB 연결 선택 */}
                    <div className="space-y-2">
                      <Label className="flex items-center gap-2 text-xs">
                        <Link2 className="h-3 w-3" />
                        DB 연결
                      </Label>
                      <Select
                        value={(query as any).externalConnectionId?.toString() || "internal"}
                        onValueChange={(value) =>
                          handleUpdateQuery(query.id, {
                            externalConnectionId: value === "internal" ? null : parseInt(value),
                          } as any)
                        }
                        disabled={isLoadingConnections}
                      >
                        <SelectTrigger className="h-8">
                          <SelectValue />
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="internal">
                            <div className="flex items-center gap-2">
                              <Database className="h-4 w-4" />
                              내부 DB (PostgreSQL)
                            </div>
                          </SelectItem>
                          {externalConnections.length > 0 && (
                            <>
                              <div className="px-2 py-1.5 text-xs font-semibold text-muted-foreground">외부 DB</div>
                              {externalConnections.map((conn) => (
                                <SelectItem key={conn.id} value={conn.id.toString()}>
                                  <div className="flex items-center gap-2">
                                    <Database className="h-4 w-4" />
                                    {conn.connection_name}
                                    <Badge variant="outline" className="text-xs">
                                      {conn.db_type.toUpperCase()}
                                    </Badge>
                                  </div>
                                </SelectItem>
                              ))}
                            </>
                          )}
                        </SelectContent>
                      </Select>
                    </div>

                    {/* SQL 쿼리 */}
                    <div className="space-y-2">
                      <Textarea
                        value={query.sqlQuery}
                        onChange={(e) => handleUpdateQuery(query.id, { sqlQuery: e.target.value })}
                        placeholder="SELECT * FROM orders WHERE order_id = $1"
                        className="min-h-[150px] font-mono text-xs"
                      />
                    </div>

                    {/* 파라미터 입력 */}
                    {query.parameters.length > 0 && (
                      <div className="space-y-3 rounded-md border border-amber-200 bg-amber-50 p-3">
                        <div className="flex items-center gap-2">
                          <AlertCircle className="h-4 w-4 text-amber-600" />
                          <Label className="text-xs font-semibold text-yellow-800">파라미터</Label>
                        </div>
                        <div className="space-y-2">
                          {query.parameters.map((param) => {
                            const paramType = queryParamTypes[param] || "text";
                            return (
                              <div key={param} className="flex items-center gap-2">
                                <Label className="w-12 text-xs font-semibold">{param}</Label>
                                <Select
                                  value={paramType}
                                  onValueChange={(value) =>
                                    setParameterTypes({
                                      ...parameterTypes,
                                      [query.id]: {
                                        ...queryParamTypes,
                                        [param]: value,
                                      },
                                    })
                                  }
                                >
                                  <SelectTrigger className="h-8 w-24">
                                    <SelectValue />
                                  </SelectTrigger>
                                  <SelectContent>
                                    <SelectItem value="text">텍스트</SelectItem>
                                    <SelectItem value="number">숫자</SelectItem>
                                    <SelectItem value="date">날짜</SelectItem>
                                  </SelectContent>
                                </Select>
                                <Input
                                  type={paramType === "number" ? "number" : paramType === "date" ? "date" : "text"}
                                  placeholder="값"
                                  className="h-8 flex-1"
                                  value={queryParams[param] || ""}
                                  onChange={(e) =>
                                    setParameterValues({
                                      ...parameterValues,
                                      [query.id]: {
                                        ...queryParams,
                                        [param]: e.target.value,
                                      },
                                    })
                                  }
                                />
                              </div>
                            );
                          })}
                        </div>
                      </div>
                    )}

                    {/* SQL 검증 경고 메시지 */}
                    {!queryValidation.isValid && queryValidation.errorMessage && (
                      <Alert variant="destructive">
                        <AlertCircle className="h-4 w-4" />
                        <AlertDescription className="text-xs">{queryValidation.errorMessage}</AlertDescription>
                      </Alert>
                    )}

                    {/* 테스트 실행 */}
                    <Button
                      size="sm"
                      variant="default"
                      className="w-full bg-destructive hover:bg-destructive"
                      onClick={() => handleTestQuery(query)}
                      disabled={!queryValidation.isValid || isTestRunning[query.id] || !isAllParametersFilled(query)}
                    >
                      <Play className="mr-2 h-4 w-4" />
                      {isTestRunning[query.id] ? "실행 중..." : "실행"}
                    </Button>

                    {/* 결과 필드 */}
                    {testResult && (
                      <div className="space-y-2 rounded-md border border-emerald-200 bg-emerald-50 p-3">
                        <Label className="text-xs font-semibold text-emerald-800">결과 필드</Label>
                        <div className="flex flex-wrap gap-2">
                          {testResult.fields.map((field) => (
                            <Badge key={field} variant="default" className="bg-teal-500">
                              {field}
                            </Badge>
                          ))}
                        </div>
                        <p className="text-xs text-emerald-700">{testResult.rows.length}건의 데이터가 조회되었습니다.</p>
                      </div>
                    )}
                  </AccordionContent>
                </AccordionItem>
              );
            })}
          </Accordion>
        ) : (
          <div className="flex flex-col items-center justify-center py-8 text-center">
            <Database className="mb-2 h-12 w-12 text-muted-foreground/50" />
            <p className="text-sm text-muted-foreground">
              쿼리를 추가하여 리포트에
              <br />
              데이터를 연결하세요
            </p>
          </div>
        )}
      </div>
    </ScrollArea>
  );
}
