"use client";

import * as React from "react";
import { useParams } from "next/navigation";
import { useTranslation } from "@/i18n/client";

import { ClientDataTable } from "../client-data-table/data-table";
import {
  getColumns,
  DataTableRowAction,
  DataTableColumnJSON,
  ColumnType,
} from "./form-data-table-columns";

import type { DataTableAdvancedFilterField } from "@/types/table";
import { Button } from "../ui/button";
import { Download, Loader, Save, Upload } from "lucide-react";
import { toast } from "sonner";
import { syncMissingTags, updateFormDataInDB } from "@/lib/forms/services";
import { UpdateTagSheet } from "./update-form-sheet";

import ExcelJS from "exceljs";
import { saveAs } from "file-saver";
import { FormDataReportTempUploadDialog } from "./form-data-report-temp-upload-dialog";
import { FormDataReportDialog } from "./form-data-report-dialog";
import { FormDataReportBatchDialog } from "./form-data-report-batch-dialog";

interface GenericData {
  [key: string]: any;
}

export interface DynamicTableProps {
  dataJSON: GenericData[];
  columnsJSON: DataTableColumnJSON[];
  contractItemId: number;
  formCode: string;
  formId: number;
}

export default function DynamicTable({
  dataJSON,
  columnsJSON,
  contractItemId,
  formCode,
  formId,
}: DynamicTableProps) {
  console.log({ columnsJSON });
  const params = useParams();
  const lng = (params?.lng as string) || "ko";
  const { t } = useTranslation(lng, "translation");

  const [rowAction, setRowAction] =
    React.useState<DataTableRowAction<GenericData> | null>(null);
  const [tableData, setTableData] = React.useState<GenericData[]>(
    () => dataJSON
  );
  const [isPending, setIsPending] = React.useState(false);
  const [isSaving, setIsSaving] = React.useState(false);
  const [tempUpDialog, setTempUpDialog] = React.useState(false);
  const [reportData, setReportData] = React.useState<GenericData[]>([]);
  const [batchDownDialog, setBatchDownDialog] = React.useState(false);

  // Reference to the table instance
  const tableRef = React.useRef(null);

  const columns = React.useMemo(
    () => getColumns<GenericData>({ columnsJSON, setRowAction, setReportData }),
    [columnsJSON, setRowAction, setReportData]
  );

  function mapColumnTypeToAdvancedFilterType(
    columnType: ColumnType
  ): DataTableAdvancedFilterField<GenericData>["type"] {
    switch (columnType) {
      case "STRING":
        return "text";
      case "NUMBER":
        return "number";
      case "LIST":
        // "select"로 하셔도 되고 "multi-select"로 하셔도 됩니다.
        return "select";
      // 그 외 다른 타입들도 적절히 추가 매핑
      default:
        // 예: 못 매핑한 경우 기본적으로 "text" 적용
        return "text";
    }
  }

  const advancedFilterFields = React.useMemo<
    DataTableAdvancedFilterField<GenericData>[]
  >(() => {
    return columnsJSON.map((col) => ({
      id: col.key,
      label: col.label,
      type: mapColumnTypeToAdvancedFilterType(col.type),
      options:
        col.type === "LIST"
          ? col.options?.map((v) => ({ label: v, value: v }))
          : undefined,
    }));
  }, [columnsJSON]);

  // 1) 태그 불러오기 (기존)
  async function handleSyncTags() {
    try {
      setIsPending(true);
      const result = await syncMissingTags(contractItemId, formCode);

      // Prepare the toast messages based on what changed
      const changes = [];
      if (result.createdCount > 0)
        changes.push(`${result.createdCount}건 태그 생성`);
      if (result.updatedCount > 0)
        changes.push(`${result.updatedCount}건 태그 업데이트`);
      if (result.deletedCount > 0)
        changes.push(`${result.deletedCount}건 태그 삭제`);

      if (changes.length > 0) {
        // If any changes were made, show success message and reload
        toast.success(`동기화 완료: ${changes.join(", ")}`);
        location.reload();
      } else {
        // If no changes were made, show an info message
        toast.info("변경사항이 없습니다. 모든 태그가 최신 상태입니다.");
      }
    } catch (err) {
      console.error(err);
      toast.error("태그 동기화 중 에러가 발생했습니다.");
    } finally {
      setIsPending(false);
    }
  }
  // 2) Excel Import (새로운 기능)
  async function handleImportExcel(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0];
    if (!file) return;

    try {
      setIsPending(true);

      // 기존 테이블 데이터의 tagNumber 목록 (이미 있는 태그)
      const existingTagNumbers = new Set(tableData.map((d) => d.tagNumber));

      const workbook = new ExcelJS.Workbook();
      const arrayBuffer = await file.arrayBuffer();
      await workbook.xlsx.load(arrayBuffer);

      const worksheet = workbook.worksheets[0];

      // (A) 헤더 파싱 (Error 열 추가 전에 먼저 체크)
      const headerRow = worksheet.getRow(1);
      const headerRowValues = headerRow.values as ExcelJS.CellValue[];

      // 디버깅용 로그
      console.log("원본 헤더 값:", headerRowValues);

      // Excel의 헤더와 columnsJSON의 label 매핑 생성
      // Excel의 행은 1부터 시작하므로 headerRowValues[0]은 undefined
      const headerToIndexMap = new Map<string, number>();
      for (let i = 1; i < headerRowValues.length; i++) {
        const headerValue = String(headerRowValues[i] || "").trim();
        if (headerValue) {
          headerToIndexMap.set(headerValue, i);
        }
      }

      // (B) 헤더 검사
      let headerErrorMessage = "";

      // (1) "columnsJSON에 있는데 엑셀에 없는" 라벨
      columnsJSON.forEach((col) => {
        const label = col.label;
        if (!headerToIndexMap.has(label)) {
          headerErrorMessage += `Column "${label}" is missing. `;
        }
      });

      // (2) "엑셀에는 있는데 columnsJSON에 없는" 라벨 검사
      headerToIndexMap.forEach((index, headerLabel) => {
        const found = columnsJSON.some((col) => col.label === headerLabel);
        if (!found) {
          headerErrorMessage += `Unexpected column "${headerLabel}" found in Excel. `;
        }
      });

      // (C) 이제 Error 열 추가
      const lastColIndex = worksheet.columnCount + 1;
      worksheet.getRow(1).getCell(lastColIndex).value = "Error";

      // 헤더 에러가 있으면 기록 후 다운로드하고 중단
      if (headerErrorMessage) {
        headerRow.getCell(lastColIndex).value = headerErrorMessage.trim();

        const outBuffer = await workbook.xlsx.writeBuffer();
        saveAs(new Blob([outBuffer]), `import-check-result_${Date.now()}.xlsx`);

        toast.error(`Header mismatch found. Please check downloaded file.`);
        return;
      }

      // -- 여기까지 왔다면, 헤더는 문제 없음 --

      // 컬럼 키-인덱스 매핑 생성 (실제 데이터 행 파싱용)
      // columnsJSON의 key와 Excel 열 인덱스 간의 매핑
      const keyToIndexMap = new Map<string, number>();
      columnsJSON.forEach((col) => {
        const index = headerToIndexMap.get(col.label);
        if (index !== undefined) {
          keyToIndexMap.set(col.key, index);
        }
      });

      // 데이터 파싱
      const importedData: GenericData[] = [];
      const lastRowNumber = worksheet.lastRow?.number || 1;
      let errorCount = 0;

      // 실제 데이터 행 파싱
      for (let rowNum = 2; rowNum <= lastRowNumber; rowNum++) {
        const row = worksheet.getRow(rowNum);
        const rowValues = row.values as ExcelJS.CellValue[];
        if (!rowValues || rowValues.length <= 1) continue; // 빈 행 스킵

        let errorMessage = "";
        const rowObj: Record<string, any> = {};

        // 각 열에 대해 처리
        columnsJSON.forEach((col) => {
          const colIndex = keyToIndexMap.get(col.key);
          if (colIndex === undefined) return;

          const cellValue = rowValues[colIndex] ?? "";
          let stringVal = String(cellValue).trim();

          // 타입별 검사
          switch (col.type) {
            case "STRING":
              if (!stringVal && col.key === "tagNumber") {
                errorMessage += `[${col.label}] is empty. `;
              }
              rowObj[col.key] = stringVal;
              break;

            case "NUMBER":
              if (stringVal) {
                const num = parseFloat(stringVal);
                if (isNaN(num)) {
                  errorMessage += `[${col.label}] '${stringVal}' is not a valid number. `;
                } else {
                  rowObj[col.key] = num;
                }
              } else {
                rowObj[col.key] = null;
              }
              break;

            case "LIST":
              if (
                stringVal &&
                col.options &&
                !col.options.includes(stringVal)
              ) {
                errorMessage += `[${
                  col.label
                }] '${stringVal}' not in ${col.options.join(", ")}. `;
              }
              rowObj[col.key] = stringVal;
              break;

            default:
              rowObj[col.key] = stringVal;
              break;
          }
        });

        // tagNumber 검사
        const tagNum = rowObj["tagNumber"];
        if (!tagNum) {
          errorMessage += `No tagNumber found. `;
        } else if (!existingTagNumbers.has(tagNum)) {
          errorMessage += `TagNumber '${tagNum}' is not in current data. `;
        }

        if (errorMessage) {
          row.getCell(lastColIndex).value = errorMessage.trim();
          errorCount++;
        } else {
          importedData.push(rowObj);
        }
      }

      // 에러가 있으면 재다운로드 후 import 중단
      if (errorCount > 0) {
        const outBuffer = await workbook.xlsx.writeBuffer();
        saveAs(new Blob([outBuffer]), `import-check-result_${Date.now()}.xlsx`);
        toast.error(
          `There are ${errorCount} error row(s). Please check downloaded file.`
        );
        return;
      }

      // 에러 없으니 tableData 병합
      setTableData((prev) => {
        const newDataMap = new Map<string, GenericData>();

        // 기존 데이터를 맵에 추가
        prev.forEach((item) => {
          if (item.tagNumber) {
            newDataMap.set(item.tagNumber, { ...item });
          }
        });

        // 임포트 데이터로 기존 데이터 업데이트
        importedData.forEach((item) => {
          const tag = item.tagNumber;
          if (!tag) return;
          const oldItem = newDataMap.get(tag) || {};
          newDataMap.set(tag, { ...oldItem, ...item });
        });

        return Array.from(newDataMap.values());
      });

      toast.success(`Imported ${importedData.length} rows successfully.`);
    } catch (err) {
      console.error("Excel import error:", err);
      toast.error("Excel import failed.");
    } finally {
      setIsPending(false);
      e.target.value = "";
    }
  }

  // 3) Save -> 서버에 전체 tableData를 저장
  async function handleSave() {
    try {
      setIsSaving(true);

      // 유효성 검사
      const invalidData = tableData.filter((item) => !item.tagNumber?.trim());
      if (invalidData.length > 0) {
        toast.error(
          `태그 번호가 없는 항목이 ${invalidData.length}개 있습니다.`
        );
        return;
      }

      // 서버 액션 호출
      const result = await updateFormDataInDB(
        formCode,
        contractItemId,
        tableData
      );

      if (result.success) {
        toast.success(result.message);
      } else {
        toast.error(result.message);
      }
    } catch (err) {
      console.error("Save error:", err);
      toast.error("데이터 저장 중 오류가 발생했습니다.");
    } finally {
      setIsSaving(false);
    }
  }

  // 4) NEW: Excel Export with data validation for select columns using a hidden validation sheet
  async function handleExportExcel() {
    try {
      setIsPending(true);

      // Create a new workbook
      const workbook = new ExcelJS.Workbook();

      // 데이터 시트 생성
      const worksheet = workbook.addWorksheet("Data");

      // 유효성 검사용 숨김 시트 생성
      const validationSheet = workbook.addWorksheet("ValidationData");
      validationSheet.state = "hidden"; // 시트 숨김 처리

      // 1. 유효성 검사 시트에 select 옵션 추가
      const selectColumns = columnsJSON.filter(
        (col) => col.type === "LIST" && col.options && col.options.length > 0
      );

      // 유효성 검사 범위 저장 맵 (컬럼 키 -> 유효성 검사 범위)
      const validationRanges = new Map<string, string>();

      selectColumns.forEach((col, idx) => {
        const colIndex = idx + 1;
        const colLetter = validationSheet.getColumn(colIndex).letter;

        // 헤더 추가 (컬럼 레이블)
        validationSheet.getCell(`${colLetter}1`).value = col.label;

        // 옵션 추가
        if (col.options) {
          col.options.forEach((option, optIdx) => {
            validationSheet.getCell(`${colLetter}${optIdx + 2}`).value = option;
          });

          // 유효성 검사 범위 저장 (ValidationData!$A$2:$A$4 형식)
          validationRanges.set(
            col.key,
            `ValidationData!${colLetter}$2:${colLetter}${
              col.options.length + 1
            }`
          );
        }
      });

      // 2. 데이터 시트에 헤더 추가
      const headers = columnsJSON.map((col) => col.label);
      worksheet.addRow(headers);

      // 헤더 스타일 적용
      const headerRow = worksheet.getRow(1);
      headerRow.font = { bold: true };
      headerRow.alignment = { horizontal: "center" };
      headerRow.eachCell((cell) => {
        cell.fill = {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFCCCCCC" },
        };
      });

      // 3. 데이터 행 추가
      tableData.forEach((row) => {
        const rowValues = columnsJSON.map((col) => {
          const value = row[col.key];
          return value !== undefined && value !== null ? value : "";
        });
        worksheet.addRow(rowValues);
      });

      // 4. 데이터 유효성 검사 적용
      const maxRows = 5000; // 데이터 유효성 검사를 적용할 최대 행 수

      columnsJSON.forEach((col, idx) => {
        if (col.type === "LIST" && validationRanges.has(col.key)) {
          const colLetter = worksheet.getColumn(idx + 1).letter;
          const validationRange = validationRanges.get(col.key)!;

          // 유효성 검사 정의
          const validation = {
            type: "list" as const,
            allowBlank: true,
            formulae: [validationRange],
            showErrorMessage: true,
            errorStyle: "warning" as const,
            errorTitle: "유효하지 않은 값",
            error: "목록에서 값을 선택해주세요.",
          };

          // 모든 데이터 행에 유효성 검사 적용 (최대 maxRows까지)
          for (
            let rowIdx = 2;
            rowIdx <= Math.min(tableData.length + 1, maxRows);
            rowIdx++
          ) {
            worksheet.getCell(`${colLetter}${rowIdx}`).dataValidation =
              validation;
          }

          // 빈 행에도 적용 (최대 maxRows까지)
          if (tableData.length + 1 < maxRows) {
            for (
              let rowIdx = tableData.length + 2;
              rowIdx <= maxRows;
              rowIdx++
            ) {
              worksheet.getCell(`${colLetter}${rowIdx}`).dataValidation =
                validation;
            }
          }
        }
      });

      // 5. 컬럼 너비 자동 조정
      columnsJSON.forEach((col, idx) => {
        const column = worksheet.getColumn(idx + 1);

        // 최적 너비 계산
        let maxLength = col.label.length;
        tableData.forEach((row) => {
          const value = row[col.key];
          if (value !== undefined && value !== null) {
            const valueLength = String(value).length;
            if (valueLength > maxLength) {
              maxLength = valueLength;
            }
          }
        });

        // 너비 설정 (최소 10, 최대 50)
        column.width = Math.min(Math.max(maxLength + 2, 10), 50);
      });

      // 6. 파일 다운로드
      const buffer = await workbook.xlsx.writeBuffer();
      saveAs(
        new Blob([buffer]),
        `${formCode}_data_${new Date().toISOString().slice(0, 10)}.xlsx`
      );

      toast.success("Excel 내보내기 완료!");
    } catch (err) {
      console.error("Excel export error:", err);
      toast.error("Excel 내보내기 실패.");
    } finally {
      setIsPending(false);
    }
  }

  return (
    <>
      <ClientDataTable
        data={tableData}
        columns={columns}
        advancedFilterFields={advancedFilterFields}
        // tableRef={tableRef}
      >
        {/* 버튼 그룹 */}
        <div className="flex items-center gap-2">
          {/* 태그 불러오기 버튼 */}
          <Button
            variant="default"
            size="sm"
            onClick={() => setBatchDownDialog(true)}
          >
            Batch
          </Button>
          <Button
            variant="default"
            size="sm"
            onClick={() => setTempUpDialog(true)}
          >
            Template Upload
          </Button>
          <Button
            variant="default"
            size="sm"
            onClick={handleSyncTags}
            disabled={isPending}
          >
            {isPending && (
              <Loader className="mr-2 size-4 animate-spin" aria-hidden="true" />
            )}
            Sync Tags
          </Button>

          {/* IMPORT 버튼 (파일 선택) */}
          <Button asChild variant="outline" size="sm" disabled={isPending}>
            <label>
              <Upload className="size-4" />
              Import
              <input
                type="file"
                accept=".xlsx,.xls"
                onChange={handleImportExcel}
                style={{ display: "none" }}
              />
            </label>
          </Button>

          {/* EXPORT 버튼 (새로 추가) */}
          <Button
            variant="outline"
            size="sm"
            onClick={handleExportExcel}
            disabled={isPending}
          >
            <Download className="mr-2 size-4" />
            Export Template
          </Button>

          {/* SAVE 버튼 */}
          <Button
            variant="outline"
            size="sm"
            onClick={handleSave}
            disabled={isPending || isSaving}
          >
            {isSaving ? (
              <>
                <Loader className="mr-2 size-4 animate-spin" />
                저장 중...
              </>
            ) : (
              <>
                <Save className="mr-2 size-4" />
                Save
              </>
            )}
          </Button>
        </div>
      </ClientDataTable>

      <UpdateTagSheet
        open={rowAction?.type === "update"}
        onOpenChange={(open) => {
          if (!open) setRowAction(null);
        }}
        columns={columnsJSON}
        rowData={rowAction?.row.original ?? null}
        formCode={formCode}
        contractItemId={contractItemId}
      />
      {tempUpDialog && (
        <FormDataReportTempUploadDialog
          open={tempUpDialog}
          setOpen={setTempUpDialog}
          packageId={contractItemId}
          formCode={formCode}
          formId={formId}
          uploaderType="vendor"
        />
      )}

      {reportData.length > 0 && (
        <FormDataReportDialog
          columnsJSON={columnsJSON}
          reportData={reportData}
          setReportData={setReportData}
          packageId={contractItemId}
          formCode={formCode}
          formId={formId}
        />
      )}

      {batchDownDialog && (
        <FormDataReportBatchDialog
          open={batchDownDialog}
          setOpen={setBatchDownDialog}
          columnsJSON={columnsJSON}
          reportData={tableData}
          packageId={contractItemId}
          formCode={formCode}
          formId={formId}
        />
      )}
    </>
  );
}


