"use client"

import * as React from "react"
import type {
  DataTableAdvancedFilterField,
  Filter,
  FilterOperator,
  JoinOperator,
} from "@/types/table"
import { type Table } from "@tanstack/react-table"
import {
  CalendarIcon,
  Check,
  ChevronsUpDown,
  GripVertical,
  ListFilter,
  Trash2,
} from "lucide-react"
import { customAlphabet } from "nanoid"

import { getDefaultFilterOperator, getFilterOperators } from "@/lib/data-table"
import { cn, formatDate } from "@/lib/utils"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from "@/components/ui/command"
import {
  FacetedFilter,
  FacetedFilterContent,
  FacetedFilterEmpty,
  FacetedFilterGroup,
  FacetedFilterInput,
  FacetedFilterItem,
  FacetedFilterList,
  FacetedFilterTrigger,
} from "@/components/ui/faceted-filter"
import { Input } from "@/components/ui/input"
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover"
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"
import {
  Sortable,
  SortableDragHandle,
  SortableItem,
} from "@/components/ui/sortable"


interface DataTableAdvancedFilterProps<TData> {
  table: Table<TData>
  filterFields: DataTableAdvancedFilterField<TData>[]
  debounceMs?: number
}

export function ClientDataTableAdvancedFilter<TData>({
  table,
  filterFields,
  debounceMs = 300,
}: DataTableAdvancedFilterProps<TData>) {
  const popoverId = React.useId()


  // 1) local filter state
  const [filters, setFilters] = React.useState<Filter<TData>[]>([])

  // 2) local joinOperator (and/or)
  const [joinOperator, setJoinOperator] = React.useState<JoinOperator>("and")

  // 3) Sync to table
  React.useEffect(() => {
    const newColumnFilters = filters.map((f) => {
      // 모든 타입에 대해 operator와 value를 함께 전달
      return {
        id: String(f.id),
        value: {
          operator: f.operator,
          value: f.type === "number" ? parseFloat(String(f.value)) : f.value,
        }
      }
    })
    
    if (joinOperator === "and") {
      table.setColumnFilters(newColumnFilters)
      table.setGlobalFilter(undefined) // globalFilter 클리어
    } else {
      table.setColumnFilters([]) // columnFilters 클리어
      
      // globalFilterFn이 기대하는 형태로 변환
      const globalFilters = filters.map((f) => ({
        columnId: String(f.id),
        filterValue: {
          operator: f.operator,
          value: f.type === "number" ? parseFloat(String(f.value)) : f.value,
        },
        type: f.type
      }))
      
      table.setGlobalFilter({
        filters: globalFilters,
        joinOperator
      })
    }
  }, [filters, joinOperator, table])


  function addFilter() {
    if (!filterFields.length) return
    const firstField = filterFields[0]

    setFilters((prev) => [
      ...prev,
      {
        id: firstField.id,
        type: firstField.type,
        operator: getDefaultFilterOperator(firstField.type),
        value: "",
        rowId: customAlphabet(
          "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
          6
        )(),
      },
    ])
  }

  function updateFilter(rowId: string, patch: Partial<Filter<TData>>) {
    setFilters((prev) =>
      prev.map((f) => (f.rowId === rowId ? { ...f, ...patch } : f))
    )
  }

  function removeFilter(rowId: string) {
    setFilters((prev) => prev.filter((f) => f.rowId !== rowId))
  }

  function moveFilter(activeIndex: number, overIndex: number) {
    setFilters((prev) => {
      const arr = [...prev]
      const [removed] = arr.splice(activeIndex, 1)
      if (!removed) return prev
      arr.splice(overIndex, 0, removed)
      return arr
    })
  }

  /**
   * Render the input UI for each filter type (text, select, date, etc.)
   */
  function renderFilterInput(filter: Filter<TData>) {

    const fieldDef = filterFields.find((f) => f.id === filter.id)
    if (!fieldDef) return null

    // For "isEmpty"/"isNotEmpty", no input needed
    if (filter.operator === "isEmpty" || filter.operator === "isNotEmpty") {
      return (
        <div
          id={filter.id}
          role="status"
          aria-live="polite"
          aria-label={`${fieldDef.label} filter is ${filter.operator === "isEmpty" ? "empty" : "not empty"}`}
          className="h-8 w-full rounded border border-dashed"
        />
      )
    }

    switch (filter.type) {
      case "text":
      case "number":
        return (
          <Input
            id={fieldDef.id}
            type={filter.type}
            aria-label={`${fieldDef.label} filter value`}
            aria-describedby={`${fieldDef.id}-description`}
            placeholder={fieldDef.placeholder ?? "Enter..."}
            className="h-8 w-full focus:outline-none !important focus:ring-offset-4 !important"
            defaultValue={
              typeof filter.value === "string" ? filter.value : undefined
            }
            onChange={(event) =>
              updateFilter(
                filter.rowId,
                { value: event.target.value },
              )
            }
          />
        )
      case "select":
        return (
          <FacetedFilter>
            <FacetedFilterTrigger asChild>
              <Button
                // id={inputId}
                variant="outline"
                size="sm"
                aria-label={`${fieldDef.label} filter value`}
                // aria-controls={`${inputId}-listbox`}
                className="h-8 w-full justify-start gap-2 rounded px-1.5 text-left text-muted-foreground hover:text-muted-foreground"
              >
                {filter.value && typeof filter.value === "string" ? (
                  <Badge
                    variant="secondary"
                    className="rounded-sm px-1 font-normal"
                  >
                    {fieldDef?.options?.find(
                      (option) => option.value === filter.value
                    )?.label || filter.value}
                  </Badge>
                ) : (
                  <>
                    {fieldDef.placeholder ?? "Select an option..."}
                    <ChevronsUpDown className="size-4" aria-hidden="true" />
                  </>
                )}
              </Button>
            </FacetedFilterTrigger>
            <FacetedFilterContent className="w-[12.5rem]">
              <FacetedFilterInput placeholder={fieldDef.label} />
              <FacetedFilterList>
                <FacetedFilterEmpty>{"No options"}</FacetedFilterEmpty>
                <FacetedFilterGroup>
                  {fieldDef.options?.map((opt) => (
                    <FacetedFilterItem
                      key={opt.value}
                      value={String(opt.value)}
                      selected={filter.value === opt.value}
                      onSelect={(val) => {
                        updateFilter(filter.rowId, { value: val })
                      }}
                    >
                      {opt.label}
                    </FacetedFilterItem>
                  ))}
                </FacetedFilterGroup>
              </FacetedFilterList>
            </FacetedFilterContent>
          </FacetedFilter>
        )

      case "multi-select":
        const selectedValues = new Set(
          Array.isArray(filter.value) ? filter.value : []
        )

        return (
          <FacetedFilter>
            <FacetedFilterTrigger asChild>
              <Button
                id={filter.id}
                variant="outline"
                size="sm"
                aria-label={`${filter.id} filter values`}
                aria-controls={`${filter.id}-listbox`}
                className="h-8 w-full justify-between gap-2 rounded px-1.5 text-left text-muted-foreground hover:text-muted-foreground"
              >
                <>
                  {selectedValues.size === 0 && (
                    <>
                      {"Select options"}
                      <ChevronsUpDown className="size-4" aria-hidden="true" />
                    </>
                  )}
                </>
                {selectedValues?.size > 0 && (
                  <div className="flex items-center">
                    <Badge
                      variant="secondary"
                      className="rounded-sm px-1 font-normal lg:hidden"
                    >
                      {selectedValues.size}
                    </Badge>
                    <div className="hidden min-w-0 gap-1 lg:flex">
                      {selectedValues.size > 2 ? (
                        <Badge
                          variant="secondary"
                          className="rounded-sm px-1 font-normal"
                        >
                          {selectedValues.size} selected
                        </Badge>
                      ) : (
                        fieldDef?.options
                          ?.filter((option) => selectedValues.has(String(option.value)))
                          .map((option) => (
                            <Badge
                              variant="secondary"
                              key={option.value}
                              className="truncate rounded-sm px-1 font-normal"
                            >
                              {option.label}
                            </Badge>
                          ))
                      )}
                    </div>
                  </div>
                )}
              </Button>
            </FacetedFilterTrigger>
            <FacetedFilterContent
              id={`${filter.id}-listbox`}
              className="w-[12.5rem] origin-[var(--radix-popover-content-transform-origin)]"
            >
              <FacetedFilterInput
                aria-label={`Search ${fieldDef?.label} options`}
                placeholder={fieldDef?.label ?? "Search options..."}
              />
              <FacetedFilterList>
                <FacetedFilterEmpty>No options found.</FacetedFilterEmpty>
                <FacetedFilterGroup>
                  {fieldDef?.options?.map((option) => (
                    <FacetedFilterItem
                      key={option.value}
                      value={String(option.value)}
                      selected={selectedValues.has(String(option.value))}
                      onSelect={(value) => {
                        const currentValue = Array.isArray(filter.value)
                          ? filter.value
                          : []
                        const newValue = currentValue.includes(value)
                          ? currentValue.filter((v) => v !== value)
                          : [...currentValue, value]
                        updateFilter(
                          filter.rowId,
                          { value: newValue },
                        )
                      }}
                    >
                      {option.icon && (
                        <option.icon
                          className="mr-2 size-4 text-muted-foreground"
                          aria-hidden="true"
                        />
                      )}
                      <span>{option.label}</span>
                      {option.count && (
                        <span className="ml-auto flex size-4 items-center justify-center font-mono text-xs">
                          {option.count}
                        </span>
                      )}
                    </FacetedFilterItem>
                  ))}
                </FacetedFilterGroup>
              </FacetedFilterList>
            </FacetedFilterContent>
          </FacetedFilter>
        )

      case "date":
        const dateValue = Array.isArray(filter.value)
          ? filter.value.filter(Boolean)
          : [filter.value, filter.value].filter(Boolean)

        const displayValue =
          filter.operator === "isBetween" && dateValue.length === 2
            ? `${formatDate(dateValue[0] ?? new Date())} - ${formatDate(
              dateValue[1] ?? new Date()
            )}`
            : dateValue[0]
              ? formatDate(dateValue[0])
              : "Pick a date"

        return (
          <Popover>
            <PopoverTrigger asChild>
              <Button
                id={fieldDef.id}
                variant="outline"
                size="sm"
                aria-label={`${fieldDef.label} date filter`}
                aria-controls={`${fieldDef.id}-calendar`}
                className={cn(
                  "h-8 w-full justify-start gap-2 rounded text-left font-normal",
                  !filter.value && "text-muted-foreground"
                )}
              >
                <CalendarIcon
                  className="size-3.5 shrink-0"
                  aria-hidden="true"
                />
                <span className="truncate">{displayValue}</span>
              </Button>
            </PopoverTrigger>
            <PopoverContent
              id={`${fieldDef.id}-calendar`}
              align="start"
              className="w-auto p-0"
            >
              {filter.operator === "isBetween" ? (
                <Calendar
                  id={`${fieldDef.id}-calendar`}
                  mode="range"
                  aria-label={`Select ${fieldDef.label} date range`}
                  selected={
                    dateValue.length === 2
                      ? {
                        from: new Date(dateValue[0] ?? ""),
                        to: new Date(dateValue[1] ?? ""),
                      }
                      : {
                        from: new Date(),
                        to: new Date(),
                      }
                  }
                  onSelect={(date) => {
                    updateFilter(
                      filter.rowId,
                      {
                        value: date
                          ? [
                            date.from?.toISOString() ?? "",
                            date.to?.toISOString() ?? "",
                          ]
                          : [],
                      },
                    )
                  }}
                  initialFocus
                  numberOfMonths={1}
                />
              ) : (
                <Calendar
                  id={`${fieldDef.id}-calendar`}
                  mode="single"
                  aria-label={`Select ${fieldDef.label} date`}
                  selected={dateValue[0] ? new Date(dateValue[0]) : undefined}
                  onSelect={(date) => {
                    updateFilter(
                      filter.rowId,
                      { value: date?.toISOString() ?? "" },
                    )

                    setTimeout(() => {
                      document.getElementById(fieldDef.id)?.click()
                    }, 0)
                  }}
                  initialFocus
                />
              )}
            </PopoverContent>
          </Popover>
        )
      case "boolean": {
        if (Array.isArray(filter.value)) return null

        return (
          <Select
            value={filter.value}
            onValueChange={(value) =>
              updateFilter(filter.rowId, { value })
            }
          >
            <SelectTrigger
              id={fieldDef.id}
              aria-label={`${fieldDef.label} boolean filter`}
              aria-controls={`${fieldDef.id}-listbox`}
              className="h-8 w-full rounded bg-transparent"
            >
              <SelectValue placeholder={filter.value ? "True" : "False"} />
            </SelectTrigger>
            <SelectContent id={`${fieldDef.id}-listbox`}>
              <SelectItem value="true">True</SelectItem>
              <SelectItem value="false">False</SelectItem>
            </SelectContent>
          </Select>
        )
      }
      default:
        return null
    }
  }


  const filterCount = filters.length

  return (
    <Sortable
      value={filters.map((f) => ({ id: f.rowId }))}
      onMove={({ activeIndex, overIndex }) => moveFilter(activeIndex, overIndex)}
    >
      <Popover>
        <PopoverTrigger asChild>
          <Button variant="outline" size="sm" className="gap-2">
            <ListFilter className="h-4 w-4" />
            {"Filters"}
            {filterCount > 0 && (
              <Badge variant="secondary" className="ml-1">
                {filterCount}
              </Badge>
            )}
          </Button>
        </PopoverTrigger>

        <PopoverContent
          id={popoverId}
          align="start"
          className="flex w-[36rem] max-w-[calc(100vw-3rem)] flex-col gap-3 p-4"
        >
          {filterCount > 0 ? (
            <h4 className="font-medium">
              {"Filters"}
            </h4>
          ) : (
            <div>
              <h4 className="font-medium">
                {"No filters applied"}
              </h4>
              <p className="text-sm text-muted-foreground">
                {"Add filters below"}
              </p>
            </div>
          )}

          {/* Filter list */}
          <div className="flex max-h-60 flex-col gap-2 overflow-y-auto pr-1">
            {filters.map((filter, index) => (
              <SortableItem key={filter.rowId} value={filter.rowId} asChild>
                <div className="flex items-center gap-2">
                  <div className="w-24 text-center">
                    {index === 0 ? (
                      <span className="text-sm text-muted-foreground">
                        {"Where"}
                      </span>
                    ) : index === 1 ? (
                      <Select
                        value={(joinOperator)}
                        onValueChange={(val) => setJoinOperator(val as JoinOperator)}
                      >
                        <SelectTrigger className="h-8 w-24 lowercase text-sm">
                          <SelectValue />
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="and">{"AND"}</SelectItem>
                          <SelectItem value="or">{"OR"}</SelectItem>
                        </SelectContent>
                      </Select>
                    ) : (
                      <span className="text-sm text-muted-foreground uppercase">
                        {joinOperator === "and"
                          ? "AND"
                          : "OR"}
                      </span>
                    )}
                  </div>

                  {/* Field (column) selection */}
                  <Popover modal>
                    <PopoverTrigger asChild>
                      <Button variant="outline" size="sm" className="h-8 w-32 justify-between">
                        {
                          filterFields.find((f) => f.id === filter.id)?.label ??
                          "Search fields..."
                        }
                        <ChevronsUpDown className="h-4 w-4 opacity-50" />
                      </Button>
                    </PopoverTrigger>
                    <PopoverContent className="w-40 p-0">
                      <Command>
                        <CommandInput placeholder={"Select field"} />
                        <CommandList>
                          <CommandEmpty>{"No fields found."}</CommandEmpty>
                          <CommandGroup>
                            {filterFields.map((ff) => (
                              <CommandItem
                                key={ff.id as string}
                                value={String(ff.id)}
                                onSelect={(val) => {
                                  const newField = filterFields.find((x) => x.id === val)
                                  if (!newField) return
                                  updateFilter(filter.rowId, {
                                    id: newField.id,
                                    type: newField.type,
                                    operator: getDefaultFilterOperator(newField.type),
                                    value: "",
                                  })
                                }}
                              >
                                {ff.label}
                                <Check
                                  className={cn(
                                    "ml-auto h-4 w-4",
                                    ff.id === filter.id ? "opacity-100" : "opacity-0"
                                  )}
                                />
                              </CommandItem>
                            ))}
                          </CommandGroup>
                        </CommandList>
                      </Command>
                    </PopoverContent>
                  </Popover>

                  {/* Operator selection */}
                  <Select
                    value={filter.operator}
                    onValueChange={(val: FilterOperator) => {
                      updateFilter(filter.rowId, {
                        operator: val,
                        value:
                          val === "isEmpty" || val === "isNotEmpty" ? "" : filter.value,
                      })
                    }}
                  >
                    <SelectTrigger className="h-8 w-28 text-sm">
                      <SelectValue />
                    </SelectTrigger>
                    <SelectContent>
                      {getFilterOperators(filter.type).map((op) => (
                        <SelectItem key={op.value} value={op.value}>
                          {op.label}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>

                  {/* The actual filter input */}
                  <div className="flex-1">{renderFilterInput(filter)}</div>

                  {/* Remove button */}
                  <Button
                    variant="outline"
                    size="icon"
                    onClick={() => removeFilter(filter.rowId)}
                    className="h-8 w-8"
                  >
                    <Trash2 className="h-4 w-4" />
                  </Button>

                  {/* Drag handle */}
                  <SortableDragHandle variant="outline" size="icon" className="h-8 w-8">
                    <GripVertical className="h-4 w-4" />
                  </SortableDragHandle>
                </div>
              </SortableItem>
            ))}
          </div>

          {/* Footer: Add filter / Reset */}
          <div className="flex items-center gap-2">
            <Button size="sm" onClick={addFilter}>
              {"Add filter"}
            </Button>
            {filterCount > 0 && (
              <Button
                size="sm"
                variant="outline"
                onClick={() => {
                  setFilters([])
                  setJoinOperator("and")
                }}
              >
                {"Reset"}
              </Button>
            )}
          </div>
        </PopoverContent>
      </Popover>
    </Sortable>
  )
}