"use client";

import React, { useState, useEffect } from "react";
import { ChartDataSource, QueryResult, KeyValuePair } from "../types";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Plus, X, Play, AlertCircle } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { ExternalDbConnectionAPI, ExternalApiConnection } from "@/lib/api/externalDbConnection";
import { getApiUrl } from "@/lib/utils/apiUrl";

// 개별 API 소스 인터페이스
interface ApiSource {
  id: string;
  endpoint: string;
  headers: KeyValuePair[];
  queryParams: KeyValuePair[];
  jsonPath?: string;
}

interface ApiConfigProps {
  dataSource: ChartDataSource;
  onChange: (updates: Partial<ChartDataSource>) => void;
  onTestResult?: (result: QueryResult) => void;
}

/**
 * REST API 설정 컴포넌트
 * - API 엔드포인트 설정
 * - 헤더 및 쿼리 파라미터 추가
 * - JSON Path 설정
 */
export function ApiConfig({ dataSource, onChange, onTestResult }: ApiConfigProps) {
  const [testing, setTesting] = useState(false);
  const [testResult, setTestResult] = useState<QueryResult | null>(null);
  const [testError, setTestError] = useState<string | null>(null);
  const [apiConnections, setApiConnections] = useState<ExternalApiConnection[]>([]);
  const [selectedConnectionId, setSelectedConnectionId] = useState<string>("");

  // 외부 API 커넥션 목록 로드
  useEffect(() => {
    const loadApiConnections = async () => {
      const connections = await ExternalDbConnectionAPI.getApiConnections({ is_active: "Y" });
      setApiConnections(connections);
    };
    loadApiConnections();
  }, []);

  // 외부 커넥션 선택 핸들러
  const handleConnectionSelect = async (connectionId: string) => {
    setSelectedConnectionId(connectionId);

    if (!connectionId || connectionId === "manual") return;

    const connection = await ExternalDbConnectionAPI.getApiConnectionById(Number(connectionId));
    if (!connection) {
      console.error("커넥션을 찾을 수 없습니다:", connectionId);
      return;
    }

    console.log("불러온 커넥션:", connection);

    // 커넥션 설정을 API 설정에 자동 적용
    // base_url과 endpoint_path를 조합하여 전체 URL 생성
    const fullEndpoint = connection.endpoint_path
      ? `${connection.base_url}${connection.endpoint_path}`
      : connection.base_url;

    console.log("전체 엔드포인트:", fullEndpoint);

    const updates: Partial<ChartDataSource> = {
      endpoint: fullEndpoint,
    };

    const headers: KeyValuePair[] = [];
    const queryParams: KeyValuePair[] = [];

    // 기본 헤더가 있으면 적용
    if (connection.default_headers && Object.keys(connection.default_headers).length > 0) {
      Object.entries(connection.default_headers).forEach(([key, value]) => {
        headers.push({
          id: `header_${Date.now()}_${Math.random()}`,
          key,
          value,
        });
      });
      console.log("기본 헤더 적용:", headers);
    }

    // 인증 설정이 있으면 헤더 또는 쿼리 파라미터에 추가
    if (connection.auth_type && connection.auth_type !== "none" && connection.auth_config) {
      console.log("인증 설정:", connection.auth_type, connection.auth_config);

      if (connection.auth_type === "bearer" && connection.auth_config.token) {
        headers.push({
          id: `header_${Date.now()}_auth`,
          key: "Authorization",
          value: `Bearer ${connection.auth_config.token}`,
        });
        console.log("Bearer 토큰 추가");
      } else if (connection.auth_type === "api-key") {
        console.log("API Key 설정:", connection.auth_config);

        if (connection.auth_config.keyName && connection.auth_config.keyValue) {
          if (connection.auth_config.keyLocation === "header") {
            headers.push({
              id: `header_${Date.now()}_apikey`,
              key: connection.auth_config.keyName,
              value: connection.auth_config.keyValue,
            });
            console.log(`API Key 헤더 추가: ${connection.auth_config.keyName}=${connection.auth_config.keyValue}`);
          } else if (connection.auth_config.keyLocation === "query") {
            queryParams.push({
              id: `param_${Date.now()}_apikey`,
              key: connection.auth_config.keyName,
              value: connection.auth_config.keyValue,
            });
            console.log(
              `API Key 쿼리 파라미터 추가: ${connection.auth_config.keyName}=${connection.auth_config.keyValue}`,
            );
          }
        }
      } else if (
        connection.auth_type === "basic" &&
        connection.auth_config.username &&
        connection.auth_config.password
      ) {
        const basicAuth = btoa(`${connection.auth_config.username}:${connection.auth_config.password}`);
        headers.push({
          id: `header_${Date.now()}_basic`,
          key: "Authorization",
          value: `Basic ${basicAuth}`,
        });
        console.log("Basic Auth 추가");
      }
    }

    updates.type = "api"; // ⭐ 중요: type을 api로 명시
    updates.method = (connection.default_method as "GET" | "POST" | "PUT" | "PATCH" | "DELETE") || "GET"; // 커넥션에 설정된 메서드 사용
    updates.headers = headers;
    updates.queryParams = queryParams;
    
    // Request Body가 있으면 적용
    if (connection.default_body) {
      updates.body = connection.default_body;
    }
    
    // 외부 커넥션 ID 저장 (백엔드에서 인증 정보 조회용)
    updates.externalConnectionId = connection.id;
    
    console.log("최종 업데이트:", updates);

    onChange(updates);
  };

  // 헤더를 배열로 정규화 (객체 형식 호환)
  const normalizeHeaders = (): KeyValuePair[] => {
    if (!dataSource.headers) return [];
    if (Array.isArray(dataSource.headers)) return dataSource.headers;
    // 객체 형식이면 배열로 변환
    return Object.entries(dataSource.headers as Record<string, string>).map(([key, value]) => ({
      id: `header_${Date.now()}_${Math.random()}`,
      key,
      value,
    }));
  };

  // 헤더 추가
  const addHeader = () => {
    const headers = normalizeHeaders();
    onChange({
      headers: [...headers, { id: `header_${Date.now()}`, key: "", value: "" }],
    });
  };

  // 헤더 제거
  const removeHeader = (id: string) => {
    const headers = normalizeHeaders();
    onChange({ headers: headers.filter((h) => h.id !== id) });
  };

  // 헤더 업데이트
  const updateHeader = (id: string, updates: Partial<KeyValuePair>) => {
    const headers = normalizeHeaders();
    onChange({
      headers: headers.map((h) => (h.id === id ? { ...h, ...updates } : h)),
    });
  };

  // 쿼리 파라미터를 배열로 정규화 (객체 형식 호환)
  const normalizeQueryParams = (): KeyValuePair[] => {
    if (!dataSource.queryParams) return [];
    if (Array.isArray(dataSource.queryParams)) return dataSource.queryParams;
    // 객체 형식이면 배열로 변환
    return Object.entries(dataSource.queryParams as Record<string, string>).map(([key, value]) => ({
      id: `param_${Date.now()}_${Math.random()}`,
      key,
      value,
    }));
  };

  // 쿼리 파라미터 추가
  const addQueryParam = () => {
    const queryParams = normalizeQueryParams();
    onChange({
      queryParams: [...queryParams, { id: `param_${Date.now()}`, key: "", value: "" }],
    });
  };

  // 쿼리 파라미터 제거
  const removeQueryParam = (id: string) => {
    const queryParams = normalizeQueryParams();
    onChange({ queryParams: queryParams.filter((p) => p.id !== id) });
  };

  // 쿼리 파라미터 업데이트
  const updateQueryParam = (id: string, updates: Partial<KeyValuePair>) => {
    const queryParams = normalizeQueryParams();
    onChange({
      queryParams: queryParams.map((p) => (p.id === id ? { ...p, ...updates } : p)),
    });
  };

  // API 테스트
  const testApi = async () => {
    if (!dataSource.endpoint) {
      setTestError("API URL을 입력하세요");
      return;
    }

    // 타일맵 URL 감지 (이미지 파일이므로 테스트 불가)
    const isTilemapUrl = 
      dataSource.endpoint.includes('{z}') && 
      dataSource.endpoint.includes('{y}') && 
      dataSource.endpoint.includes('{x}');
    
    if (isTilemapUrl) {
      setTestError("타일맵 URL은 테스트할 수 없습니다. 지도 위젯에서 직접 확인하세요.");
      return;
    }

    setTesting(true);
    setTestError(null);
    setTestResult(null);

    try {
      // 쿼리 파라미터 구성
      const params: Record<string, string> = {};
      const normalizedQueryParams = normalizeQueryParams();
      normalizedQueryParams.forEach(({ key, value }) => {
        if (key && value) {
          params[key] = value;
        }
      });

      // 헤더 구성
      const headers: Record<string, string> = {};
      const normalizedHeaders = normalizeHeaders();
      normalizedHeaders.forEach(({ key, value }) => {
        if (key && value) {
          headers[key] = value;
        }
      });

      // 요청 메서드 결정
      const requestMethod = dataSource.method || "GET";
      
      // Request Body 파싱 (POST, PUT, PATCH인 경우)
      let requestBody: any = undefined;
      if (["POST", "PUT", "PATCH"].includes(requestMethod) && dataSource.body) {
        try {
          requestBody = JSON.parse(dataSource.body);
        } catch {
          throw new Error("Request Body가 올바른 JSON 형식이 아닙니다");
        }
      }

      // 백엔드 프록시를 통한 외부 API 호출 (CORS 우회)
      const response = await fetch(getApiUrl("/api/dashboards/fetch-external-api"), {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          url: dataSource.endpoint,
          method: requestMethod,
          headers: headers,
          queryParams: params,
          body: requestBody,
          externalConnectionId: dataSource.externalConnectionId, // DB 토큰 등 인증 정보 조회용
        }),
      });

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      const apiResponse = await response.json();

      if (!apiResponse.success) {
        throw new Error(apiResponse.message || "외부 API 호출 실패");
      }

      let apiData = apiResponse.data;

      // 텍스트 응답인 경우 파싱
      if (apiData && typeof apiData === "object" && "text" in apiData && typeof apiData.text === "string") {
        const textData = apiData.text;
        
        // CSV 형식 파싱 (기상청 API)
        if (textData.includes("#START7777") || textData.includes(",")) {
          const lines = textData.split("\n").filter((line) => line.trim() && !line.startsWith("#"));
          const parsedRows = lines.map((line) => {
            const values = line.split(",").map((v) => v.trim());
            return {
              reg_up: values[0] || "",
              reg_up_ko: values[1] || "",
              reg_id: values[2] || "",
              reg_ko: values[3] || "",
              tm_fc: values[4] || "",
              tm_ef: values[5] || "",
              wrn: values[6] || "",
              lvl: values[7] || "",
              cmd: values[8] || "",
              ed_tm: values[9] || "",
            };
          });
          apiData = parsedRows;
        } else {
          // 일반 텍스트는 그대로 반환
          apiData = [{ text: textData }];
        }
      }

      // JSON Path 처리
      let data = apiData;
      if (dataSource.jsonPath) {
        const paths = dataSource.jsonPath.split(".");
        for (const path of paths) {
          // 배열인 경우 인덱스 접근, 객체인 경우 키 접근
          if (data === null || data === undefined) {
            throw new Error(`JSON Path "${dataSource.jsonPath}"에서 데이터를 찾을 수 없습니다 (null/undefined)`);
          }
          
          if (Array.isArray(data)) {
            // 배열인 경우 숫자 인덱스로 접근 시도
            const index = parseInt(path);
            if (!isNaN(index) && index >= 0 && index < data.length) {
              data = data[index];
            } else {
              throw new Error(`JSON Path "${dataSource.jsonPath}"에서 배열 인덱스 "${path}"를 찾을 수 없습니다`);
            }
          } else if (typeof data === "object" && path in data) {
            data = (data as Record<string, any>)[path];
          } else {
            throw new Error(`JSON Path "${dataSource.jsonPath}"에서 "${path}" 키를 찾을 수 없습니다`);
          }
        }
      }

      // 배열이 아니면 배열로 변환
      const rows = Array.isArray(data) ? data : [data];

      if (rows.length === 0) {
        throw new Error("API 응답에 데이터가 없습니다");
      }

      // 컬럼 추출 및 타입 분석
      const firstRow = rows[0];
      
      // firstRow가 null이거나 객체가 아닌 경우 처리
      if (firstRow === null || firstRow === undefined) {
        throw new Error("API 응답의 첫 번째 행이 비어있습니다");
      }
      
      if (typeof firstRow !== "object" || Array.isArray(firstRow)) {
        throw new Error("API 응답 데이터가 올바른 객체 형식이 아닙니다");
      }
      
      const columns = Object.keys(firstRow);

      // 각 컬럼의 타입 분석
      const columnTypes: Record<string, string> = {};
      columns.forEach((col) => {
        const value = firstRow[col];
        if (value === null || value === undefined) {
          columnTypes[col] = "null";
        } else if (Array.isArray(value)) {
          columnTypes[col] = "array";
        } else if (typeof value === "object") {
          columnTypes[col] = "object";
        } else if (typeof value === "number") {
          columnTypes[col] = "number";
        } else if (typeof value === "boolean") {
          columnTypes[col] = "boolean";
        } else {
          columnTypes[col] = "string";
        }
      });

      const queryResult: QueryResult = {
        columns,
        rows,
        totalRows: rows.length,
        executionTime: 0,
        columnTypes, // 타입 정보 추가
      };

      setTestResult(queryResult);
      onTestResult?.(queryResult);
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : "알 수 없는 오류가 발생했습니다";
      setTestError(errorMessage);
    } finally {
      setTesting(false);
    }
  };

  return (
    <div className="space-y-4">
      {/* 외부 커넥션 선택 - 항상 표시 */}
      <div className="space-y-2">
        <Label className="text-xs font-medium text-foreground">외부 커넥션 (선택)</Label>
        <Select value={selectedConnectionId} onValueChange={handleConnectionSelect}>
          <SelectTrigger className="h-8 text-xs">
            <SelectValue placeholder="저장된 커넥션 선택" />
          </SelectTrigger>
          <SelectContent className="z-[9999]" position="popper" sideOffset={4}>
            <SelectItem value="manual" className="text-xs">
              직접 입력
            </SelectItem>
            {apiConnections.length > 0 ? (
              apiConnections.map((conn) => (
                <SelectItem key={conn.id} value={String(conn.id)} className="text-xs">
                  {conn.connection_name}
                  {conn.description && <span className="ml-1.5 text-[10px] text-muted-foreground">({conn.description})</span>}
                </SelectItem>
              ))
            ) : (
              <SelectItem value="no-connections" disabled className="text-xs text-muted-foreground">
                등록된 커넥션이 없습니다
              </SelectItem>
            )}
          </SelectContent>
        </Select>
        <p className="text-[11px] text-muted-foreground">저장한 REST API 설정을 불러올 수 있습니다</p>
      </div>

      {/* HTTP 메서드 및 API URL */}
      <div className="space-y-1.5">
        <Label className="text-xs font-medium text-foreground">API URL *</Label>
        <div className="flex gap-2">
          <Select
            value={dataSource.method || "GET"}
            onValueChange={(value) => onChange({ method: value as "GET" | "POST" | "PUT" | "PATCH" | "DELETE" })}
          >
            <SelectTrigger className="h-8 w-24 text-xs">
              <SelectValue placeholder="GET" />
            </SelectTrigger>
            <SelectContent className="z-[9999]">
              <SelectItem value="GET" className="text-xs">GET</SelectItem>
              <SelectItem value="POST" className="text-xs">POST</SelectItem>
              <SelectItem value="PUT" className="text-xs">PUT</SelectItem>
              <SelectItem value="PATCH" className="text-xs">PATCH</SelectItem>
              <SelectItem value="DELETE" className="text-xs">DELETE</SelectItem>
            </SelectContent>
          </Select>
          <Input
            type="url"
            placeholder="https://api.example.com/data"
            value={dataSource.endpoint || ""}
            onChange={(e) => onChange({ endpoint: e.target.value })}
            className="h-8 flex-1 text-xs"
          />
        </div>
        <p className="text-[11px] text-muted-foreground">
          전체 URL 또는 base_url 이후 경로를 입력하세요 (외부 커넥션 선택 시 base_url 자동 입력)
        </p>
      </div>

      {/* Request Body (POST, PUT, PATCH인 경우) */}
      {["POST", "PUT", "PATCH"].includes(dataSource.method || "") && (
        <div className="space-y-1.5">
          <Label className="text-xs font-medium text-foreground">Request Body (JSON)</Label>
          <textarea
            placeholder='{"key": "value"}'
            value={dataSource.body || ""}
            onChange={(e) => onChange({ body: e.target.value })}
            className="h-24 w-full rounded-md border border-input bg-background px-3 py-2 font-mono text-xs ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
          />
          <p className="text-[11px] text-muted-foreground">
            JSON 형식으로 요청 본문을 입력하세요
          </p>
        </div>
      )}

      {/* 쿼리 파라미터 */}
      <div className="space-y-2">
        <div className="flex items-center justify-between">
          <Label className="text-xs font-medium text-foreground">URL 쿼리 파라미터</Label>
          <Button variant="outline" size="sm" onClick={addQueryParam} className="h-6 text-[11px]">
            <Plus className="mr-1 h-3 w-3" />
            추가
          </Button>
        </div>

        {(() => {
          const params = normalizeQueryParams();
          return params.length > 0 ? (
            <div className="space-y-1.5">
              {params.map((param) => (
                <div key={param.id} className="flex gap-1.5">
                  <Input
                    placeholder="key"
                    value={param.key}
                    onChange={(e) => updateQueryParam(param.id, { key: e.target.value })}
                    className="h-7 flex-1 text-xs"
                  />
                  <Input
                    placeholder="value"
                    value={param.value}
                    onChange={(e) => updateQueryParam(param.id, { value: e.target.value })}
                    className="h-7 flex-1 text-xs"
                  />
                  <button
                    onClick={() => removeQueryParam(param.id)}
                    className="flex h-7 w-7 items-center justify-center rounded hover:bg-muted"
                  >
                    <X className="h-3 w-3" />
                  </button>
                </div>
              ))}
            </div>
          ) : (
            <p className="py-2 text-center text-[11px] text-muted-foreground">추가된 파라미터가 없습니다</p>
          );
        })()}

        <p className="text-[11px] text-muted-foreground">예: category=electronics, limit=10</p>
      </div>

      {/* 헤더 */}
      <div className="space-y-2">
        <div className="flex items-center justify-between">
          <Label className="text-xs font-medium text-foreground">요청 헤더</Label>
          <Button variant="outline" size="sm" onClick={addHeader}>
            <Plus className="mr-1 h-3 w-3" />
            추가
          </Button>
        </div>

        {/* 빠른 헤더 템플릿 */}
        <div className="flex flex-wrap gap-2">
          <Button
            variant="outline"
            size="sm"
            onClick={() => {
              const headers = normalizeHeaders();
              onChange({
                headers: [...headers, { id: `header_${Date.now()}`, key: "Authorization", value: "" }],
              });
            }}
          >
            + Authorization
          </Button>
          <Button
            variant="outline"
            size="sm"
            onClick={() => {
              const headers = normalizeHeaders();
              onChange({
                headers: [...headers, { id: `header_${Date.now()}`, key: "Content-Type", value: "application/json" }],
              });
            }}
          >
            + Content-Type
          </Button>
        </div>

        {(() => {
          const headers = normalizeHeaders();
          return headers.length > 0 ? (
            <div className="space-y-2">
              {headers.map((header) => (
                <div key={header.id} className="flex gap-2">
                  <Input
                    placeholder="Header Name"
                    value={header.key}
                    onChange={(e) => updateHeader(header.id, { key: e.target.value })}
                    className="flex-1"
                  />
                  <Input
                    placeholder="Header Value"
                    value={header.value}
                    onChange={(e) => updateHeader(header.id, { value: e.target.value })}
                    className="flex-1"
                    type={header.key.toLowerCase().includes("auth") ? "password" : "text"}
                  />
                  <Button variant="ghost" size="icon" onClick={() => removeHeader(header.id)}>
                    <X className="h-4 w-4" />
                  </Button>
                </div>
              ))}
            </div>
          ) : (
            <p className="py-2 text-center text-sm text-muted-foreground">추가된 헤더가 없습니다</p>
          );
        })()}
      </div>

      {/* JSON Path */}
      <div className="space-y-2">
        <Label className="text-xs font-medium text-foreground">JSON Path (선택)</Label>
        <Input
          placeholder="data.results"
          value={dataSource.jsonPath || ""}
          onChange={(e) => onChange({ jsonPath: e.target.value })}
        />
        <p className="text-[11px] text-muted-foreground">
          JSON 응답에서 데이터 배열의 경로 (예: data.results, items, response.data)
          <br />
          비워두면 전체 응답을 사용합니다
        </p>
      </div>

      {/* 자동 새로고침 (HTTP Polling) */}
      <div className="space-y-1.5">
        <Label className="text-xs font-medium text-foreground">자동 새로고침 간격</Label>
        <Select
          value={(dataSource.refreshInterval || 0).toString()}
          onValueChange={(value) => onChange({ refreshInterval: parseInt(value) })}
        >
          <SelectTrigger className="h-8 text-xs">
            <SelectValue placeholder="간격 선택" />
          </SelectTrigger>
          <SelectContent className="z-[9999]">
            <SelectItem value="0" className="text-xs">없음 (수동)</SelectItem>
            <SelectItem value="5" className="text-xs">5초</SelectItem>
            <SelectItem value="10" className="text-xs">10초</SelectItem>
            <SelectItem value="30" className="text-xs">30초</SelectItem>
            <SelectItem value="60" className="text-xs">1분</SelectItem>
            <SelectItem value="300" className="text-xs">5분</SelectItem>
          </SelectContent>
        </Select>
        <p className="text-[11px] text-muted-foreground">
          설정된 간격마다 자동으로 API를 호출하여 데이터를 갱신합니다
        </p>
      </div>

      {/* 테스트 버튼 */}
      <div className="flex justify-end">
        <Button onClick={testApi} disabled={!dataSource.endpoint || testing}>
          {testing ? (
            <>
              <div className="mr-2 h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" />
              테스트 중...
            </>
          ) : (
            <>
              <Play className="mr-2 h-4 w-4" />
              API 테스트
            </>
          )}
        </Button>
      </div>

      {/* 테스트 오류 */}
      {testError && (
        <div className="rounded bg-destructive/10 px-2 py-2">
          <div className="flex items-start gap-2">
            <AlertCircle className="mt-0.5 h-5 w-5 flex-shrink-0 text-destructive" />
            <div>
              <div className="text-sm font-medium text-destructive">API 호출 실패</div>
              <div className="mt-1 text-sm text-destructive">{testError}</div>
            </div>
          </div>
        </div>
      )}

      {/* 테스트 결과 */}
      {testResult && (
        <div className="rounded bg-success/10 px-2 py-2">
          <div className="mb-2 text-sm font-medium text-success">API 호출 성공</div>
          <div className="space-y-1 text-xs text-success">
            <div>총 {testResult.rows.length}개의 데이터를 불러왔습니다</div>
            <div>컬럼: {testResult.columns.join(", ")}</div>
          </div>
        </div>
      )}
    </div>
  );
}
