"use client"

import * as React from "react"
import { type Table } from "@tanstack/react-table"
import { toast } from "sonner"
import ExcelJS from "exceljs"
import { saveAs } from "file-saver"

import { Button } from "@/components/ui/button"
import { Download, Upload, Loader2, RefreshCcw } from "lucide-react"
import { Tag, TagSubfields } from "@/db/schema/vendorData"
import { exportTagsToExcel } from "./tags-export"
import { AddTagDialog } from "./add-tag-dialog"
import { fetchTagSubfieldOptions, getTagNumberingRules, } from "@/lib/tag-numbering/service"
import { bulkCreateTags, getClassOptions, getProjectIdFromContractItemId, getSubfieldsByTagType } from "../service"
import { DeleteTagsDialog } from "./delete-tags-dialog"
import { useRouter } from "next/navigation" // Add this import
import { decryptWithServerAction } from "@/components/drm/drmUtils"

// 태그 번호 검증을 위한 인터페이스
interface TagNumberingRule {
  attributesId: string;
  attributesDescription: string;
  expression: string | null;
  delimiter: string | null;
  sortOrder: number;
}

interface TagOption {
  code: string;
  label: string;
}

interface ClassOption {
  code: string;
  label: string;
  tagTypeCode: string;
  tagTypeDescription: string;
}

// 서브필드 정의
interface SubFieldDef {
  name: string;
  label: string;
  type: "select" | "text";
  options?: { value: string; label: string }[];
  expression?: string;
  delimiter?: string;
}

interface TagsTableToolbarActionsProps {
  /** react-table 객체 */
  table: Table<Tag>
  /** 현재 선택된 패키지 ID */
  packageCode: string
  projectCode: string
  /** 현재 태그 목록(상태) */
  tableData: Tag[]
  /** 태그 목록을 갱신하는 setState */
  selectedMode: string
}

/**
 * TagsTableToolbarActions:
 * - Import 버튼 -> Excel 파일 파싱 & 유효성 검사 (Class 기반 검증 추가)
 * - 에러 발생 시: state는 그대로 두고, 오류가 적힌 엑셀만 재다운로드
 * - 정상인 경우: tableData에 병합
 * - Export 버튼 -> 유효성 검사가 포함된 Excel 내보내기
 */
export function TagsTableToolbarActions({
  table,
  packageCode,
  projectCode,
  tableData,
  selectedMode
}: TagsTableToolbarActionsProps) {
  const router = useRouter() // Add this line

  const [isPending, setIsPending] = React.useState(false)
  const [isExporting, setIsExporting] = React.useState(false)
  const fileInputRef = React.useRef<HTMLInputElement>(null)

  const [isLoading, setIsLoading] = React.useState(false)
  const [syncId, setSyncId] = React.useState<string | null>(null)
  const pollingRef = React.useRef<NodeJS.Timeout | null>(null)

  // 태그 타입별 넘버링 룰 캐시
  const [tagNumberingRules, setTagNumberingRules] = React.useState<Record<string, TagNumberingRule[]>>({})
  const [tagOptionsCache, setTagOptionsCache] = React.useState<Record<string, TagOption[]>>({})

  // 클래스 옵션 및 서브필드 캐시
  const [classOptions, setClassOptions] = React.useState<ClassOption[]>([])
  const [subfieldCache, setSubfieldCache] = React.useState<Record<string, SubFieldDef[]>>({})

  // 컴포넌트 마운트 시 클래스 옵션 로드
  React.useEffect(() => {
    const loadClassOptions = async () => {
      try {
        const options = await getClassOptions(packageCode, projectCode)
        setClassOptions(options)
      } catch (error) {
        console.error("Failed to load class options:", error)
      }
    }

    loadClassOptions()
  }, [packageCode, projectCode])

  // 숨겨진 <input>을 클릭
  function handleImportClick() {
    fileInputRef.current?.click()
  }

  // 태그 넘버링 룰 가져오기
  const fetchTagNumberingRules = React.useCallback(async (tagType: string): Promise<TagNumberingRule[]> => {
    // 이미 캐시에 있으면 캐시된 값 사용
    if (tagNumberingRules[tagType]) {
      return tagNumberingRules[tagType]
    }

    try {
      // 서버 액션 직접 호출
      const rules = await getTagNumberingRules(tagType)

      // 캐시에 저장
      setTagNumberingRules(prev => ({
        ...prev,
        [tagType]: rules
      }))

      return rules
    } catch (error) {
      console.error(`Error fetching rules for ${tagType}:`, error)
      return []
    }
  }, [tagNumberingRules])

  const [projectId, setProjectId] = React.useState<number | null>(null);

  React.useEffect(() => {
    const fetchProjectId = async () => {
      if (packageCode && projectCode) {
        try {
          const pid = await getProjectIdFromContractItemId(projectCode );
          setProjectId(pid);
        } catch (error) {
          console.error("Failed to fetch project ID:", error);
          toast.error("Failed to load project data");
        }
      }
    };

    fetchProjectId();
  }, [projectCode]);

  // 특정 attributesId에 대한 옵션 가져오기
  const fetchOptions = React.useCallback(async (attributesId: string): Promise<TagOption[]> => {
    // Cache check remains the same
    if (tagOptionsCache[attributesId]) {
      return tagOptionsCache[attributesId];
    }

    try {
      // Only pass projectId if it's not null
      let options: TagOption[];
      if (projectId !== null) {
        options = await fetchTagSubfieldOptions(attributesId, projectId);
      } else {
        options = []
      }

      // Update cache
      setTagOptionsCache(prev => ({
        ...prev,
        [attributesId]: options
      }));

      return options;
    } catch (error) {
      console.error(`Error fetching options for ${attributesId}:`, error);
      return [];
    }
  }, [tagOptionsCache, projectId]);

  // 클래스 라벨로 태그 타입 코드 찾기
  const getTagTypeCodeByClassLabel = React.useCallback((classLabel: string): string | null => {
    const classOption = classOptions.find(opt => opt.label === classLabel)
    return classOption?.tagTypeCode || null
  }, [classOptions])

  // 태그 타입에 따른 서브필드 가져오기
  const fetchSubfieldsByTagType = React.useCallback(async (tagTypeCode: string): Promise<SubFieldDef[]> => {
    // 이미 캐시에 있으면 캐시된 값 사용
    if (subfieldCache[tagTypeCode]) {
      return subfieldCache[tagTypeCode]
    }

    try {
      const { subFields } = await getSubfieldsByTagType(tagTypeCode, projectCode)

      // API 응답을 SubFieldDef 형식으로 변환
      const formattedSubFields: SubFieldDef[] = subFields.map(field => ({
        name: field.name,
        label: field.label,
        type: field.type,
        options: field.options || [],
        expression: field.expression ?? undefined,
        delimiter: field.delimiter ?? undefined,
      }))

      // 캐시에 저장
      setSubfieldCache(prev => ({
        ...prev,
        [tagTypeCode]: formattedSubFields
      }))

      return formattedSubFields
    } catch (error) {
      console.error(`Error fetching subfields for tagType ${tagTypeCode}:`, error)
      return []
    }
  }, [subfieldCache])

  // Class 기반 태그 번호 형식 검증
  const validateTagNumberByClass = React.useCallback(async (
    tagNo: string,
    classLabel: string
  ): Promise<string> => {
    if (!tagNo) return "Tag number is empty."
    if (!classLabel) return "Class is empty."

    try {
      // 1. 클래스 라벨로 태그 타입 코드 찾기
      const tagTypeCode = getTagTypeCodeByClassLabel(classLabel)
      if (!tagTypeCode) {
        return `No tag type found for class '${classLabel}'.`
      }

      // 2. 태그 타입 코드로 서브필드 가져오기
      const subfields = await fetchSubfieldsByTagType(tagTypeCode)
      if (!subfields || subfields.length === 0) {
        return `No subfields found for tag type code '${tagTypeCode}'.`
      }

      // 3. 태그 번호를 파트별로 분석
      let remainingTagNo = tagNo
      let currentPosition = 0

      for (const field of subfields) {
        // 구분자 확인
        const delimiter = field.delimiter || ""

        // 다음 구분자 위치 또는 문자열 끝
        let nextDelimiterPos
        if (delimiter && remainingTagNo.includes(delimiter)) {
          nextDelimiterPos = remainingTagNo.indexOf(delimiter)
        } else {
          nextDelimiterPos = remainingTagNo.length
        }

        // 현재 파트 추출
        const part = remainingTagNo.substring(0, nextDelimiterPos)

        // 비어있으면 오류
        if (!part) {
          return `Empty part for field '${field.label}'.`
        }

        // 정규식 검증
        if (field.expression) {
          try {
            // 중복된 ^, $ 제거 후 다시 추가
            let cleanPattern = field.expression;

            // 시작과 끝의 ^, $ 제거
            cleanPattern = cleanPattern.replace(/^\^/, '').replace(/\$$/, '');

            // 정규식 생성 (항상 전체 매칭)
            const regex = new RegExp(`^${cleanPattern}$`);

            if (!regex.test(part)) {
              return `Part '${part}' for field '${field.label}' does not match the pattern '${field.expression}'.`;
            }
          } catch (error) {
            console.error(`Invalid regex pattern: ${field.expression}`, error);
            return `Invalid pattern for field '${field.label}': ${field.expression}`;
          }
        }
        // 선택 옵션 검증
        if (field.type === "select" && field.options && field.options.length > 0) {
          const validValues = field.options.map(opt => opt.value)
          if (!validValues.includes(part)) {
            return `'${part}' is not a valid value for field '${field.label}'. Valid options: ${validValues.join(", ")}.`
          }
        }

        // 남은 문자열 업데이트
        if (delimiter && nextDelimiterPos < remainingTagNo.length) {
          remainingTagNo = remainingTagNo.substring(nextDelimiterPos + delimiter.length)
        } else {
          remainingTagNo = ""
          break
        }
      }

      // 문자열이 남아있으면 오류
      if (remainingTagNo) {
        return `Tag number has extra parts: '${remainingTagNo}'.`
      }

      return "" // 오류 없음
    } catch (error) {
      console.error("Error validating tag number by class:", error)
      return "Error validating tag number format."
    }
  }, [getTagTypeCodeByClassLabel, fetchSubfieldsByTagType])

  // 기존 태그 번호 검증 함수 (기존 코드를 유지)
  const validateTagNumber = React.useCallback(async (tagNo: string, tagType: string): Promise<string> => {
    if (!tagNo) return "Tag number is empty."
    if (!tagType) return "Tag type is empty."

    try {
      // 1. 태그 타입에 대한 넘버링 룰 가져오기
      const rules = await fetchTagNumberingRules(tagType)
      if (!rules || rules.length === 0) {
        return `No numbering rules found for tag type '${tagType}'.`
      }

      // 2. 정렬된 룰 (sortOrder 기준)
      const sortedRules = [...rules].sort((a, b) => a.sortOrder - b.sortOrder)

      // 3. 태그 번호를 파트로 분리
      let remainingTagNo = tagNo
      let currentPosition = 0

      for (const rule of sortedRules) {
        // 마지막 룰이 아니고 구분자가 있으면
        const delimiter = rule.delimiter || ""

        // 다음 구분자 위치 찾기 또는 문자열 끝
        let nextDelimiterPos
        if (delimiter && remainingTagNo.includes(delimiter)) {
          nextDelimiterPos = remainingTagNo.indexOf(delimiter)
        } else {
          nextDelimiterPos = remainingTagNo.length
        }

        // 현재 파트 추출
        const part = remainingTagNo.substring(0, nextDelimiterPos)

        // 표현식이 있으면 검증
        if (rule.expression) {
          const regex = new RegExp(`^${rule.expression}$`)
          if (!regex.test(part)) {
            return `Part '${part}' does not match the pattern '${rule.expression}' for ${rule.attributesDescription}.`
          }
        }

        // 옵션이 있는 경우 유효한 코드인지 확인
        const options = await fetchOptions(rule.attributesId)
        if (options.length > 0) {
          const isValidCode = options.some(opt => opt.code === part)
          if (!isValidCode) {
            return `'${part}' is not a valid code for ${rule.attributesDescription}. Valid options: ${options.map(o => o.code).join(', ')}.`
          }
        }

        // 남은 문자열 업데이트
        if (delimiter && nextDelimiterPos < remainingTagNo.length) {
          remainingTagNo = remainingTagNo.substring(nextDelimiterPos + delimiter.length)
        } else {
          remainingTagNo = ""
          break
        }

        // 모든 룰을 처리했는데 문자열이 남아있으면 오류
        if (remainingTagNo && rule === sortedRules[sortedRules.length - 1]) {
          return `Tag number has extra parts: '${remainingTagNo}'.`
        }
      }

      // 문자열이 남아있으면 오류
      if (remainingTagNo) {
        return `Tag number has unprocessed parts: '${remainingTagNo}'.`
      }

      return "" // 오류 없음
    } catch (error) {
      console.error("Error validating tag number:", error)
      return "Error validating tag number."
    }
  }, [fetchTagNumberingRules, fetchOptions])

  /**
   * 개선된 handleFileChange 함수
   * 1) ExcelJS로 파일 파싱
   * 2) 헤더 -> meta.excelHeader 매핑
   * 3) 각 행 유효성 검사 (Class 기반 검증 추가)
   * 4) 에러 행 있으면 → 오류 메시지 기록 + 재다운로드 (상태 변경 안 함)
   * 5) 정상 행만 importedRows 로 → 병합
   */
  async function handleFileChange(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0]
    if (!file) return

    // 파일 input 초기화
    e.target.value = ""
    setIsPending(true)

    try {
      // 1) Workbook 로드
      const workbook = new ExcelJS.Workbook()
      // const arrayBuffer = await file.arrayBuffer()
      const arrayBuffer = await decryptWithServerAction(file);
      await workbook.xlsx.load(arrayBuffer)

      // 첫 번째 시트 사용
      const worksheet = workbook.worksheets[0]

      // (A) 마지막 열에 "Error" 헤더
      const lastColIndex = worksheet.columnCount + 1
      worksheet.getRow(1).getCell(lastColIndex).value = "Error"

      // (B) 엑셀 헤더 (Row1)
      const headerRowValues = worksheet.getRow(1).values as ExcelJS.CellValue[]

      // (C) excelHeader -> accessor 매핑
      const excelHeaderToAccessor: Record<string, string> = {}
      for (const col of table.getAllColumns()) {
        const meta = col.columnDef.meta as { excelHeader?: string } | undefined
        if (meta?.excelHeader) {
          const accessor = col.id as string
          excelHeaderToAccessor[meta.excelHeader] = accessor
        }
      }

      // (D) accessor -> column index
      const accessorIndexMap: Record<string, number> = {}
      for (let i = 1; i < headerRowValues.length; i++) {
        const cellVal = String(headerRowValues[i] ?? "").trim()
        if (!cellVal) continue
        const accessor = excelHeaderToAccessor[cellVal]
        if (accessor) {
          accessorIndexMap[accessor] = i
        }
      }

      let errorCount = 0
      const importedRows: Tag[] = []
      const fileTagNos = new Set<string>() // 파일 내 태그번호 중복 체크용
      const lastRow = worksheet.lastRow?.number || 1

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

        let errorMsg = ""

        // 필요한 accessorIndex
        const tagNoIndex = accessorIndexMap["tagNo"]
        const classIndex = accessorIndexMap["class"]

        // 엑셀에서 값 읽기
        const tagNo = tagNoIndex ? String(rowVals[tagNoIndex] ?? "").trim() : ""
        const classVal = classIndex ? String(rowVals[classIndex] ?? "").trim() : ""

        // A. 필수값 검사
        if (!tagNo) {
          errorMsg += `Tag No is empty. `
        }
        if (!classVal) {
          errorMsg += `Class is empty. `
        }

        // B. 중복 검사
        if (tagNo) {
          // 이미 tableData 내 존재 여부
          const dup = tableData.find(
            (t) =>  t.tagNo === tagNo
          )
          if (dup) {
            errorMsg += `TagNo '${tagNo}' already exists. `
          }

          // 이번 엑셀 파일 내 중복
          if (fileTagNos.has(tagNo)) {
            errorMsg += `TagNo '${tagNo}' is duplicated within this file. `
          } else {
            fileTagNos.add(tagNo)
          }
        }

        // C. Class 기반 형식 검증
        if (tagNo && classVal && !errorMsg) {
          // classVal 로부터 태그타입 코드 획득
          const tagTypeCode = getTagTypeCodeByClassLabel(classVal)

          if (!tagTypeCode) {
            errorMsg += `No tag type code found for class '${classVal}'. `
          } else {
            // validateTagNumberByClass( ) 안에서
            // → tagTypeCode로 서브필드 조회, 정규식 검증 등 처리
            const classValidationError = await validateTagNumberByClass(tagNo, classVal)
            if (classValidationError) {
              errorMsg += classValidationError + " "
            }
          }
        }

        // D. 에러 처리
        if (errorMsg) {
          row.getCell(lastColIndex).value = errorMsg.trim()
          errorCount++
        } else {
          // 최종 태그 타입 결정 (DB에 저장할 때 'tagType' 컬럼을 무엇으로 쓸지 결정)
          // 예: DB에서 tagType을 "CV" 같은 코드로 저장하려면
          //  const finalTagType = getTagTypeCodeByClassLabel(classVal) ?? ""
          // 혹은 "Control Valve" 같은 description을 쓰려면 classOptions에서 찾아볼 수도 있음
          const finalTagType = getTagTypeCodeByClassLabel(classVal) ?? ""

          // 정상 행을 importedRows에 추가
          importedRows.push({
            id: 0, // 임시
            packageCode: packageCode,
            projectCode: projectCode,
            formId: null,
            tagNo,
            tagType: finalTagType,     // ← 코드로 저장할지, Description으로 저장할지 결정
            class: classVal,
            description: String(rowVals[accessorIndexMap["description"] ?? 0] ?? "").trim(),
            createdAt: new Date(),
            updatedAt: new Date(),
          })
        }
      }

      // (E) 오류 행이 있으면 → 수정된 엑셀 재다운로드 & 종료
      if (errorCount > 0) {
        const outBuf = await workbook.xlsx.writeBuffer()
        const errorFile = new Blob([outBuf])
        const url = URL.createObjectURL(errorFile)
        const link = document.createElement("a")
        link.href = url
        link.download = "tag_import_errors.xlsx"
        link.click()
        URL.revokeObjectURL(url)

        toast.error(`There are ${errorCount} error row(s). Please see downloaded file.`)
        return
      }

      // 정상 행이 있으면 태그 생성 요청
      if (importedRows.length > 0) {
        const result = await bulkCreateTags(importedRows, projectCode, packageCode);
        if ("error" in result) {
          toast.error(result.error);
        } else {
          toast.success(`${result.data.createdCount}개의 태그가 성공적으로 생성되었습니다.`);
        }
      }

      toast.success(`Imported ${importedRows.length} tags successfully!`)

    } catch (err) {
      console.error(err)
      toast.error("파일 업로드 중 오류가 발생했습니다.")
    } finally {
      setIsPending(false)
    }
  }
  // 새 Export 함수 - 유효성 검사 시트를 포함한 엑셀 내보내기
  async function handleExport() {
    try {
      setIsExporting(true)

      // 유효성 검사가 포함된 새로운 엑셀 내보내기 함수 호출
      await exportTagsToExcel(table, packageCode,projectCode, {
        filename: `Tags_${packageCode}_${projectCode}`,
        excludeColumns: ["select", "actions", "createdAt", "updatedAt"],
      })

      toast.success("태그 목록이 성공적으로 내보내졌습니다.")
    } catch (error) {
      console.error("Export error:", error)
      toast.error("태그 목록 내보내기 중 오류가 발생했습니다.")
    } finally {
      setIsExporting(false)
    }
  }

  const startGetTags = async () => {
    try {
      setIsLoading(true)

      // API 엔드포인트 호출 - 작업 시작만 요청
      const response = await fetch('/api/cron/tags-plant/start', {
        method: 'POST',
        body: JSON.stringify({
          projectCode: projectCode,
          packageCode: packageCode,
          mode: selectedMode // 모드 정보 추가
        })
      })
      if (!response.ok) {
        const errorData = await response.json()
        throw new Error(errorData.error || 'Failed to start tag import')
      }

      const data = await response.json()

      // 작업 ID 저장
      if (data.syncId) {
        setSyncId(data.syncId)
        toast.info('Tag import started. This may take a while...')

        // 상태 확인을 위한 폴링 시작
        startPolling(data.syncId)
      } else {
        throw new Error('No import ID returned from server')
      }
    } catch (error) {
      console.error('Error starting tag import:', error)
      toast.error(
        error instanceof Error
          ? error.message
          : 'An error occurred while starting tag import'
      )
      setIsLoading(false)
    }
  }

  const startPolling = (id: string) => {
    // 이전 폴링이 있다면 제거
    if (pollingRef.current) {
      clearInterval(pollingRef.current)
    }

    // 5초마다 상태 확인
    pollingRef.current = setInterval(async () => {
      try {
        const response = await fetch(`/api/cron/tags-plant/status?id=${id}`)

        if (!response.ok) {
          throw new Error('Failed to get tag import status')
        }

        const data = await response.json()

        if (data.status === 'completed') {
          // 폴링 중지
          if (pollingRef.current) {
            clearInterval(pollingRef.current)
            pollingRef.current = null
          }

          router.refresh()

          // 상태 초기화
          setIsLoading(false)
          setSyncId(null)

          // 성공 메시지 표시
          toast.success(
            `Tags imported successfully! ${data.result?.processedCount || 0} items processed.`
          )

          // 테이블 데이터 업데이트
          table.resetRowSelection()
        } else if (data.status === 'failed') {
          // 에러 처리
          if (pollingRef.current) {
            clearInterval(pollingRef.current)
            pollingRef.current = null
          }

          setIsLoading(false)
          setSyncId(null)
          toast.error(data.error || 'Import failed')
        } else if (data.status === 'processing') {
          // 진행 상태 업데이트 (선택적)
          if (data.progress) {
            toast.info(`Import in progress: ${data.progress}%`, {
              id: `import-progress-${id}`,
            })
          }
        }
      } catch (error) {
        console.error('Error checking importing status:', error)
      }
    }, 5000) // 5초마다 체크
  }

  return (
    <div className="flex items-center gap-2">

      {table.getFilteredSelectedRowModel().rows.length > 0 ? (
        <DeleteTagsDialog
          tags={table
            .getFilteredSelectedRowModel()
            .rows.map((row) => row.original)}
          onSuccess={() => table.toggleAllRowsSelected(false)}
          projectCode={projectCode}
          packageCode={packageCode}
        />
      ) : null}
      <Button
        variant="samsung"
        size="sm"
        className="gap-2"
        onClick={startGetTags}
        disabled={isLoading}
      >
        <RefreshCcw className={`size-4 ${isLoading ? 'animate-spin' : ''}`} aria-hidden="true" />
        <span className="hidden sm:inline">
          {isLoading ? 'Syncing...' : 'Get Tags'}
        </span>
      </Button>

      <AddTagDialog projectCode={projectCode} packageCode={packageCode} />

      {/* Import */}
      <Button
        variant="outline"
        size="sm"
        onClick={handleImportClick}
        disabled={isPending || isExporting}
      >
        {isPending ? (
          <Loader2 className="size-4 mr-2 animate-spin" aria-hidden="true" />
        ) : (
          <Upload className="size-4 mr-2" aria-hidden="true" />
        )}
        <span className="hidden sm:inline">Import</span>
      </Button>
      <input
        ref={fileInputRef}
        type="file"
        accept=".xlsx,.xls"
        className="hidden"
        onChange={handleFileChange}
      />

      {/* Export */}
      <Button
        variant="outline"
        size="sm"
        onClick={handleExport}
        disabled={isPending || isExporting}
      >
        {isExporting ? (
          <Loader2 className="size-4 mr-2 animate-spin" aria-hidden="true" />
        ) : (
          <Download className="size-4 mr-2" aria-hidden="true" />
        )}
        <span className="hidden sm:inline">Export</span>
      </Button>
    </div>
  )
}