// components/vendor-data-plant/tags-table.tsx
"use client"

import * as React from "react"
import type {
  DataTableAdvancedFilterField,
  DataTableFilterField,
  DataTableRowAction,
} from "@/types/table"
import { useRouter } from "next/navigation"
import { toast } from "sonner"
import { Trash2, Download, Upload, Loader2, RefreshCcw, Plus } from "lucide-react"
import ExcelJS from "exceljs"
import type { Table as TanstackTable } from "@tanstack/react-table"

import { ClientDataTable } from "@/components/client-data-table/data-table"
import { getColumns } from "./tag-table-column"
import { Tag } from "@/db/schema/vendorData"
import { DeleteTagsDialog } from "./delete-tags-dialog"
import { UpdateTagSheet } from "./update-tag-sheet"
import { AddTagDialog } from "./add-tag-dialog"
import { useAtomValue } from 'jotai'
import { selectedModeAtom } from '@/atoms'
import { Skeleton } from "@/components/ui/skeleton"
import type { ColumnDef } from "@tanstack/react-table"
import { createDynamicAttributeColumns } from "../column-builder.service"
import { getAllTagsPlant, getUniqueAttributeKeys } from "../queries"
import { Button } from "@/components/ui/button"
import { exportTagsToExcel } from "./tags-export"
import { 
  bulkCreateTags, 
  getClassOptions, 
  getProjectIdFromContractItemId,
  getSubfieldsByTagType 
} from "../service"
import { decryptWithServerAction } from "@/components/drm/drmUtils"

interface TagsTableProps {
  projectCode: string
  packageCode: string
}

// 태그 넘버링 룰 인터페이스 (Import용)
interface TagNumberingRule {
  attributesId: string;
  attributesDescription: string;
  expression: string | null;
  delimiter: string | null;
  sortOrder: number;
}

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;
}

export function TagsTable({ 
  projectCode, 
  packageCode,
}: TagsTableProps) {
  const router = useRouter()
  const selectedMode = useAtomValue(selectedModeAtom)

  // 상태 관리
  const [tableData, setTableData] = React.useState<Tag[]>([])
  const [columns, setColumns] = React.useState<ColumnDef<Tag>[]>([])
  const [isLoading, setIsLoading] = React.useState(true)
  const [rowAction, setRowAction] = React.useState<DataTableRowAction<Tag> | null>(null)
  

  console.log(tableData,"tableData")

  // 선택된 행 관리
  const [selectedRowsData, setSelectedRowsData] = React.useState<Tag[]>([])
  const [clearSelection, setClearSelection] = React.useState(false)
  
  // 다이얼로그 상태
  const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false)
  const [deleteTarget, setDeleteTarget] = React.useState<Tag[]>([])
  const [addTagDialogOpen, setAddTagDialogOpen] = React.useState(false)

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

  // Sync 상태
  const [isSyncing, setIsSyncing] = React.useState(false)
  const [syncId, setSyncId] = React.useState<string | null>(null)
  const pollingRef = React.useRef<NodeJS.Timeout | null>(null)

  // Table ref for export
  const tableRef = React.useRef<TanstackTable<Tag> | null>(null)

  // Cache for validation
  const [classOptions, setClassOptions] = React.useState<ClassOption[]>([])
  const [subfieldCache, setSubfieldCache] = React.useState<Record<string, SubFieldDef[]>>({})
  const [projectId, setProjectId] = React.useState<number | null>(null)

  // Load project ID
  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)
        }
      }
    }
    fetchProjectId()
  }, [projectCode])

  // Load class options
  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])

  // 데이터 및 컬럼 로드
  React.useEffect(() => {
    async function loadTableData() {
      try {
        setIsLoading(true)

        const [tagsData, attributeKeys] = await Promise.all([
          getAllTagsPlant(projectCode, packageCode),
          getUniqueAttributeKeys(projectCode, packageCode),
        ])

        const baseColumns = getColumns({ 
          setRowAction,
          onDeleteClick: handleDeleteRow 
        })

        let dynamicColumns: ColumnDef<Tag>[] = []
        if (attributeKeys.length > 0) {
          dynamicColumns = createDynamicAttributeColumns(attributeKeys)
        }

        const actionsColumn = baseColumns.pop()
        const finalColumns = [
          ...baseColumns,
          ...dynamicColumns,
          actionsColumn
        ].filter(Boolean) as ColumnDef<Tag>[]

        setTableData(tagsData)
        setColumns(finalColumns)
      } catch (error) {
        console.error("Error loading table data:", error)
        toast.error("Failed to load table data")
        setTableData([])
        setColumns(getColumns({ 
          setRowAction,
          onDeleteClick: handleDeleteRow 
        }))
      } finally {
        setIsLoading(false)
      }
    }

    loadTableData()
  }, [projectCode, packageCode])

  // Filter fields
  const filterFields: DataTableFilterField<Tag>[] = [
    {
      id: "tagNo",
      label: "Tag Number",
      placeholder: "Filter Tag Number...",
    },
  ]

  const advancedFilterFields: DataTableAdvancedFilterField<Tag>[] = [
    {
      id: "tagNo",
      label: "Tag No",
      type: "text",
    },
    {
      id: "tagType",
      label: "Tag Type",
      type: "text",
    },
    {
      id: "description",
      label: "Description",
      type: "text",
    },
    {
      id: "class",
      label: "Class",
      type: "text",
    },
    {
      id: "createdAt",
      label: "Created at",
      type: "date",
    },
    {
      id: "updatedAt",
      label: "Updated at",
      type: "date",
    },
  ]

  // 선택된 행 개수
  const selectedRowCount = React.useMemo(() => {
    return selectedRowsData.length
  }, [selectedRowsData])

  // 개별 행 삭제
  const handleDeleteRow = React.useCallback((rowData: Tag) => {
    setDeleteTarget([rowData])
    setDeleteDialogOpen(true)
  }, [])

  // 배치 삭제
  const handleBatchDelete = React.useCallback(() => {
    if (selectedRowsData.length === 0) {
      toast.error("삭제할 항목을 선택해주세요.")
      return
    }
    setDeleteTarget(selectedRowsData)
    setDeleteDialogOpen(true)
  }, [selectedRowsData])

  // 삭제 성공 후 처리
  const handleDeleteSuccess = React.useCallback(() => {
    const tagNosToDelete = deleteTarget
      .map(item => item.tagNo)
      .filter(Boolean)

    setTableData(prev =>
      prev.filter(item => !tagNosToDelete.includes(item.tagNo))
    )

    setSelectedRowsData([])
    setClearSelection(prev => !prev)
    setDeleteTarget([])
    
    toast.success("삭제되었습니다.")
  }, [deleteTarget])

  // 클래스 라벨로 태그 타입 코드 찾기
  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, "", "")
      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, projectCode])

  // 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 {
      const tagTypeCode = getTagTypeCodeByClassLabel(classLabel)
      if (!tagTypeCode) {
        return `No tag type found for class '${classLabel}'.`
      }

      const subfields = await fetchSubfieldsByTagType(tagTypeCode)
      if (!subfields || subfields.length === 0) {
        return `No subfields found for tag type code '${tagTypeCode}'.`
      }

      let remainingTagNo = tagNo
      
      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.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])

  // Import 파일 선택
  const handleImportClick = () => {
    fileInputRef.current?.click()
  }

  // Import 파일 처리
  const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0]
    if (!file) return

    e.target.value = ""
    setIsPending(true)

    try {
      const workbook = new ExcelJS.Workbook()
      const arrayBuffer = await decryptWithServerAction(file)
      await workbook.xlsx.load(arrayBuffer)

      const worksheet = workbook.worksheets[0]
      const lastColIndex = worksheet.columnCount + 1
      worksheet.getRow(1).getCell(lastColIndex).value = "Error"

      const headerRowValues = worksheet.getRow(1).values as ExcelJS.CellValue[]

      // Excel header to accessor mapping
      const excelHeaderToAccessor: Record<string, string> = {}
      for (const col of columns) {
        const meta = col.meta as { excelHeader?: string } | undefined
        if (meta?.excelHeader) {
          const accessor = col.id as string
          excelHeaderToAccessor[meta.excelHeader] = accessor
        }
      }

      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

      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 = ""

        const tagNoIndex = accessorIndexMap["tagNo"]
        const classIndex = accessorIndexMap["class"]

        const tagNo = tagNoIndex ? String(rowVals[tagNoIndex] ?? "").trim() : ""
        const classVal = classIndex ? String(rowVals[classIndex] ?? "").trim() : ""

        if (!tagNo) {
          errorMsg += `Tag No is empty. `
        }
        if (!classVal) {
          errorMsg += `Class is empty. `
        }

        if (tagNo) {
          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)
          }
        }

        if (tagNo && classVal && !errorMsg) {
          const classValidationError = await validateTagNumberByClass(tagNo, classVal)
          if (classValidationError) {
            errorMsg += classValidationError + " "
          }
        }

        if (errorMsg) {
          row.getCell(lastColIndex).value = errorMsg.trim()
          errorCount++
        } else {
          const finalTagType = getTagTypeCodeByClassLabel(classVal) ?? ""

          importedRows.push({
            id: 0,
            packageCode: packageCode,
            projectCode: projectCode,
            formId: null,
            tagNo,
            tagType: finalTagType,
            class: classVal,
            description: String(rowVals[accessorIndexMap["description"] ?? 0] ?? "").trim(),
            createdAt: new Date(),
            updatedAt: new Date(),
          })
        }
      }

      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}개의 태그가 성공적으로 생성되었습니다.`)
          router.refresh()
        }
      }
    } catch (err) {
      console.error(err)
      toast.error("파일 업로드 중 오류가 발생했습니다.")
    } finally {
      setIsPending(false)
    }
  }

  // Export 함수
  const handleExport = async () => {
    if (!tableRef.current) {
      toast.error("테이블이 준비되지 않았습니다.")
      return
    }

    try {
      setIsExporting(true)
      await exportTagsToExcel(tableRef.current, 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)
    }
  }

  // Sync 함수
  const startGetTags = async () => {
    try {
      setIsSyncing(true)

      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()

      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'
      )
      setIsSyncing(false)
    }
  }

  const startPolling = (id: string) => {
    if (pollingRef.current) {
      clearInterval(pollingRef.current)
    }

    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()
          setIsSyncing(false)
          setSyncId(null)

          toast.success(
            `Tags imported successfully! ${data.result?.processedCount || 0} items processed.`
          )
        } else if (data.status === 'failed') {
          if (pollingRef.current) {
            clearInterval(pollingRef.current)
            pollingRef.current = null
          }

          setIsSyncing(false)
          setSyncId(null)
          toast.error(data.error || 'Import failed')
        }
      } catch (error) {
        console.error('Error checking importing status:', error)
      }
    }, 5000)
  }

  // rowAction 처리
  React.useEffect(() => {
    if (rowAction?.type === "delete") {
      handleDeleteRow(rowAction.row.original)
      setRowAction(null)
    }
  }, [rowAction, handleDeleteRow])

  // Cleanup
  React.useEffect(() => {
    return () => {
      if (pollingRef.current) {
        clearInterval(pollingRef.current)
      }
    }
  }, [])

  // 로딩 중
  if (isLoading) {
    return (
      <div className="space-y-4">
        <Skeleton className="h-10 w-full" />
        <Skeleton className="h-[500px] w-full" />
        <Skeleton className="h-10 w-full" />
      </div>
    )
  }

  return (
    <>
      <ClientDataTable
        data={tableData}
        columns={columns}
        advancedFilterFields={advancedFilterFields}
        autoSizeColumns
        onSelectedRowsChange={setSelectedRowsData}
        clearSelection={clearSelection}
        onTableReady={(table) => {
          tableRef.current = table
        }}
      >
        <div className="flex items-center gap-2">
          {/* 삭제 버튼 - 선택된 항목이 있을 때만 */}
          {selectedRowCount > 0 && (
            <Button
              variant="destructive"
              size="sm"
              onClick={handleBatchDelete}
            >
              <Trash2 className="mr-2 size-4" />
              Delete ({selectedRowCount})
            </Button>
          )}

          {/* Get Tags 버튼 */}
          <Button
            variant="samsung"
            size="sm"
            onClick={startGetTags}
            disabled={isSyncing}
          >
            <RefreshCcw className={`size-4 mr-2 ${isSyncing ? 'animate-spin' : ''}`} />
            <span className="hidden sm:inline">
              {isSyncing ? 'Syncing...' : 'Get Tags'}
            </span>
          </Button>

          {/* Add Tag 버튼 */}
          <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" />
            ) : (
              <Upload className="size-4 mr-2" />
            )}
            <span className="hidden sm:inline">Import</span>
          </Button>

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

      {/* Hidden file input */}
      <input
        ref={fileInputRef}
        type="file"
        accept=".xlsx,.xls"
        className="hidden"
        onChange={handleFileChange}
      />

      {/* Update Sheet */}
      <UpdateTagSheet
        open={rowAction?.type === "update"}
        onOpenChange={(open) => {
          if (!open) setRowAction(null)
        }}
        tag={rowAction?.row.original ?? null}
        packageCode={packageCode}
        projectCode={projectCode}
        onUpdateSuccess={(updatedValues) => {
          if (rowAction?.row.original?.tagNo) {
            const tagNo = rowAction.row.original.tagNo
            setTableData(prev =>
              prev.map(item =>
                item.tagNo === tagNo ? updatedValues : item
              )
            )
          }
        }}
      />

      {/* Delete Dialog */}
      <DeleteTagsDialog
        tags={deleteTarget}
        packageCode={packageCode}
        projectCode={projectCode}
        open={deleteDialogOpen}
        onOpenChange={(open) => {
          if (!open) {
            setDeleteDialogOpen(false)
            setDeleteTarget([])
          }
        }}
        onSuccess={handleDeleteSuccess}
        showTrigger={false}
      />

      {/* Add Tag Dialog */}
      {/* <AddTagDialog
        projectCode={projectCode}
        packageCode={packageCode}
        open={addTagDialogOpen}
        onOpenChange={setAddTagDialogOpen}
        onSuccess={() => {
          router.refresh()
        }}
      /> */}
    </>
  )
}