"use client"

import * as React from "react"
import { type Column, type Table } from "@tanstack/react-table"
import { Check, ChevronsUpDown, MoveLeft } from "lucide-react"

import { cn, toSentenceCase } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandSeparator,
} from "@/components/ui/command"
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover"

/**
 * Helper function to check if a column is a parent column (has subcolumns)
 */
function isParentColumn<TData>(column: Column<TData>): boolean {
  return column.columns && column.columns.length > 0
}

/**
 * Helper function to pin all subcolumns of a parent column
 */
function pinSubColumns<TData>(
  column: Column<TData>,
  pinType: false | "left" | "right"
): void {
  // If this is a parent column, pin all its subcolumns
  if (isParentColumn(column)) {
    column.columns.forEach((subColumn) => {
      // Recursively handle nested columns
      pinSubColumns(subColumn, pinType)
    })
  } else {
    // For leaf columns, apply the pin if possible
    if (column.getCanPin?.()) {
      column.pin?.(pinType)
    }
  }
}

/**
 * Checks if all subcolumns of a parent column are pinned to the specified side
 */
function areAllSubColumnsPinned<TData>(
  column: Column<TData>,
  pinType: "left" | "right"
): boolean {
  if (isParentColumn(column)) {
    // Check if all subcolumns are pinned
    return column.columns.every((subColumn) => 
      areAllSubColumnsPinned(subColumn, pinType)
    )
  } else {
    // For leaf columns, check if it's pinned to the specified side
    return column.getIsPinned?.() === pinType
  }
}

/**
 * Helper function to get the display name of a column
 */
function getColumnDisplayName<TData>(column: Column<TData>): string {
  // First try to use excelHeader from meta if available
  const excelHeader = column.columnDef.meta?.excelHeader
  if (excelHeader) {
    return excelHeader
  }
  
  // Fall back to converting the column ID to sentence case
  return toSentenceCase(column.id)
}

/**
 * Array of column IDs that should be auto-pinned to the left when available
 */
const AUTO_PIN_LEFT_COLUMNS = ['select']

/**
 * "Pin Left" Popover. Supports pinning both individual columns and header groups.
 */
export function PinLeftButton<TData>({ table }: { table: Table<TData> }) {
  const [open, setOpen] = React.useState(false)
  const triggerRef = React.useRef<HTMLButtonElement>(null)

  // Try to auto-pin select and action columns if they exist
  React.useEffect(() => {
    AUTO_PIN_LEFT_COLUMNS.forEach((columnId) => {
      const column = table.getColumn(columnId)
      if (column?.getCanPin?.()) {
        column.pin?.("left")
      }
    })
  }, [table])
  
  // Get all columns that can be pinned (excluding auto-pinned columns)
  const pinnableColumns = React.useMemo(() => {
    return table.getAllColumns().filter((column) => {
      // Skip auto-pinned columns
      if (AUTO_PIN_LEFT_COLUMNS.includes(column.id)) {
        return false
      }
      
      // If it's a leaf column, check if it can be pinned
      if (!isParentColumn(column)) {
        return column.getCanPin?.()
      }
      
      // If it's a parent column, check if at least one subcolumn can be pinned
      return column.columns.some((subCol) => {
        if (isParentColumn(subCol)) {
          // Recursively check nested columns
          return subCol.columns.some(c => c.getCanPin?.())
        }
        return subCol.getCanPin?.()
      })
    })
  }, [table])

  // Get flat list of all leaf columns for display
  const allPinnableLeafColumns = React.useMemo(() => {
    const leafColumns: Column<TData>[] = []
    
    // Function to recursively collect leaf columns
    const collectLeafColumns = (column: Column<TData>) => {
      if (isParentColumn(column)) {
        column.columns.forEach(collectLeafColumns)
      } else if (column.getCanPin?.() && !AUTO_PIN_LEFT_COLUMNS.includes(column.id)) {
        leafColumns.push(column)
      }
    }
    
    // Process all columns
    table.getAllColumns().forEach(collectLeafColumns)
    
    return leafColumns
  }, [table])

  // Handle column pinning
  const handleColumnPin = React.useCallback((column: Column<TData>) => {
    // For parent columns, pin/unpin all subcolumns
    if (isParentColumn(column)) {
      const allPinned = areAllSubColumnsPinned(column, "left")
      pinSubColumns(column, allPinned ? false : "left")
    } else {
      // For leaf columns, toggle pin state
      const isPinned = column.getIsPinned?.() === "left"
      column.pin?.(isPinned ? false : "left")
    }
  }, [])

  // Check if a column or its subcolumns are pinned left
  const isColumnPinned = React.useCallback((column: Column<TData>): boolean => {
    if (isParentColumn(column)) {
      return areAllSubColumnsPinned(column, "left")
    } else {
      return column.getIsPinned?.() === "left"
    }
  }, [])

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <Button
          ref={triggerRef}
          variant="outline"
          size="sm"
          className="h-8 gap-2"
        >
          <MoveLeft className="size-4" />
          
          <span className="hidden sm:inline">
            왼쪽 고정
          </span>
        </Button>
      </PopoverTrigger>
      
      <PopoverContent
        align="end"
        className="w-56 p-0"
        onCloseAutoFocus={() => triggerRef.current?.focus()}
      >
        <Command>
          <CommandInput placeholder="Search columns..." />
          <CommandList className="max-h-[300px]">
            <CommandEmpty>No columns found.</CommandEmpty>
            <CommandGroup>
              {/* Parent Columns with subcolumns */}
              {pinnableColumns
                .filter(isParentColumn)
                .map((parentColumn) => (
                  <React.Fragment key={parentColumn.id}>
                    {/* Parent column header - can pin/unpin all children at once */}
                    <CommandItem
                      onSelect={() => {
                        handleColumnPin(parentColumn)
                      }}
                      className="font-medium bg-muted/50"
                    >
                      <span className="truncate">
                        {getColumnDisplayName(parentColumn)}
                      </span>
                      <Check
                        className={cn(
                          "ml-auto size-4 shrink-0",
                          isColumnPinned(parentColumn) ? "opacity-100" : "opacity-0"
                        )}
                      />
                    </CommandItem>
                    
                    {/* Individual subcolumns */}
                    {parentColumn.columns
                      .filter(col => !isParentColumn(col) && col.getCanPin?.())
                      .map(subColumn => (
                        <CommandItem
                          key={subColumn.id}
                          onSelect={() => {
                            handleColumnPin(subColumn)
                          }}
                          className="pl-6 text-sm"
                        >
                          <span className="truncate">
                            {getColumnDisplayName(subColumn)}
                          </span>
                          <Check
                            className={cn(
                              "ml-auto size-4 shrink-0",
                              isColumnPinned(subColumn) ? "opacity-100" : "opacity-0"
                            )}
                          />
                        </CommandItem>
                      ))}
                  </React.Fragment>
                ))}
            </CommandGroup>
            
            {/* Separator if we have both parent columns and standalone leaf columns */}
            {pinnableColumns.some(isParentColumn) && 
             allPinnableLeafColumns.some(col => !pinnableColumns.find(parent => 
               isParentColumn(parent) && parent.columns.includes(col))
             ) && (
              <CommandSeparator />
            )}
            
            {/* Standalone leaf columns (not part of any parent column group) */}
            <CommandGroup>
              {allPinnableLeafColumns
                .filter(col => !pinnableColumns.find(parent => 
                  isParentColumn(parent) && parent.columns.includes(col)
                ))
                .map((column) => (
                  <CommandItem
                    key={column.id}
                    onSelect={() => {
                      handleColumnPin(column)
                    }}
                  >
                    <span className="truncate">
                      {getColumnDisplayName(column)}
                    </span>
                    <Check
                      className={cn(
                        "ml-auto size-4 shrink-0",
                        isColumnPinned(column) ? "opacity-100" : "opacity-0"
                      )}
                    />
                  </CommandItem>
                ))}
            </CommandGroup>
          </CommandList>
        </Command>
      </PopoverContent>
    </Popover>
  )
}