'use client'

import { useEffect, useMemo, useRef, useState, useCallback } from 'react'
import { UnifiedTableProps, ColumnVisibilityState, SortState, SavedView } from './types'
import { useSelection, usePagination, useFilters, useTableURL, useColumnReorder, useColumnResize } from './hooks'
import { useTableKeyboard } from './hooks/useTableKeyboard'
import { TableFilters } from './components/TableFilters'
import { BulkActionBar } from './components/BulkActionBar'
import { DataTableCore } from './components/DataTableCore'
import { TablePagination } from './components/TablePagination'
import { StandardTableToolbar } from './components/Toolbar'
import { Loader2 } from 'lucide-react'
import { cn } from '../../utils'

export function UnifiedTable<TData>({
  data,
  columns,
  tableId,
  getRowId,
  pagination: paginationConfig,
  selection: selectionConfig,
  filters: filtersConfig,
  bulkActions = [],
  rowActions = [],
  search: searchConfig,
  sorting: sortingConfig,
  columnVisibility: columnVisibilityConfig,
  columnReorder: columnReorderConfig,
  columnResize: columnResizeConfig,
  inlineEdit: inlineEditConfig,
  savedViews: savedViewsConfig,
  urlPersistence: urlPersistenceConfig,
  export: exportConfig,
  onRowClick,
  mobileConfig,
  loading = false,
  loadingRows = new Set(),
  className,
  emptyState,
  errorState,
}: UnifiedTableProps<TData>) {
  const searchInputRef = useRef<HTMLInputElement | null>(null)
  const shouldRestoreFocusRef = useRef(false)
  const tableRef = useRef<HTMLDivElement>(null)

  // URL state persistence hook
  const urlState = useTableURL({
    tableId,
    persistToUrl: urlPersistenceConfig?.enabled ?? false,
    debounceMs: urlPersistenceConfig?.debounceMs ?? 300,
  })

  // Initialize state from URL if persistence is enabled
  const initialURLState = useMemo(() => {
    if (!urlPersistenceConfig?.enabled) return null
    return urlState.getURLState()
  }, []) // Only run once on mount

  // Column visibility state
  const [columnVisibility, setColumnVisibility] = useState<ColumnVisibilityState>(() => {
    // Try to load from localStorage if persistKey is set
    if (columnVisibilityConfig?.persistKey && typeof window !== 'undefined') {
      try {
        const stored = localStorage.getItem(`table-columns-${columnVisibilityConfig.persistKey}`)
        if (stored) {
          return JSON.parse(stored)
        }
      } catch {
        // Ignore localStorage errors
      }
    }

    // Initialize default visibility
    const initial: ColumnVisibilityState = {}
    columns.forEach(col => {
      if (columnVisibilityConfig?.defaultVisible) {
        initial[col.id] = columnVisibilityConfig.defaultVisible.includes(col.id)
      } else {
        initial[col.id] = true // Default all visible
      }
    })
    return initial
  })

  // Client-side sorting state (used when no external sorting config is provided)
  const [localSort, setLocalSort] = useState<SortState>(() => {
    // Initialize from URL if available
    if (initialURLState) {
      return {
        sortBy: initialURLState.sortBy,
        sortDirection: initialURLState.sortDirection,
      }
    }
    return { sortBy: null, sortDirection: 'asc' }
  })

  // Persist column visibility
  useEffect(() => {
    if (columnVisibilityConfig?.persistKey && typeof window !== 'undefined') {
      try {
        localStorage.setItem(
          `table-columns-${columnVisibilityConfig.persistKey}`,
          JSON.stringify(columnVisibility)
        )
      } catch {
        // Ignore localStorage errors
      }
    }
  }, [columnVisibility, columnVisibilityConfig?.persistKey])

  // Toggle column visibility
  const toggleColumnVisibility = useCallback((columnId: string) => {
    // Don't allow toggling always-visible columns
    if (columnVisibilityConfig?.alwaysVisible?.includes(columnId)) {
      return
    }
    setColumnVisibility(prev => ({
      ...prev,
      [columnId]: !prev[columnId]
    }))
  }, [columnVisibilityConfig?.alwaysVisible])

  // Filter visible columns
  const visibleColumns = useMemo(() => {
    if (!columnVisibilityConfig?.enabled) {
      return columns
    }
    return columns.filter(col => columnVisibility[col.id] !== false)
  }, [columns, columnVisibility, columnVisibilityConfig?.enabled])

  // Get hideable columns for the dropdown
  const hideableColumns = useMemo(() => {
    return columns.filter(col => {
      // Can't hide if hideable is explicitly false
      if (col.hideable === false) return false
      // Can't hide if in alwaysVisible list
      if (columnVisibilityConfig?.alwaysVisible?.includes(col.id)) return false
      return true
    })
  }, [columns, columnVisibilityConfig?.alwaysVisible])

  // Column reordering hook
  const columnReorder = useColumnReorder({
    columns: visibleColumns,
    initialOrder: columnReorderConfig?.initialOrder,
    enabled: columnReorderConfig?.enabled ?? false,
    onOrderChange: columnReorderConfig?.onOrderChange,
  })

  // Final columns to display (ordered if reorder enabled)
  const displayColumns = columnReorderConfig?.enabled
    ? columnReorder.orderedColumns
    : visibleColumns

  // Column resize hook
  const columnResize = useColumnResize({
    enabled: columnResizeConfig?.enabled ?? false,
    initialWidths: columnResizeConfig?.initialWidths,
    minWidth: columnResizeConfig?.minWidth ?? 50,
    onWidthChange: columnResizeConfig?.onWidthChange,
  })

  // Determine sorting state and handler
  const sortingEnabled = sortingConfig?.enabled ?? true // Default to enabled
  const currentSortBy = sortingConfig?.value?.sortBy ?? localSort.sortBy
  const currentSortDirection = sortingConfig?.value?.sortDirection ?? localSort.sortDirection

  const handleSort = useCallback((columnId: string) => {
    const newDirection = currentSortBy === columnId && currentSortDirection === 'asc' ? 'desc' : 'asc'
    const newSort = { sortBy: columnId, sortDirection: newDirection as 'asc' | 'desc' }

    if (sortingConfig?.onChange) {
      sortingConfig.onChange(newSort)
    } else {
      setLocalSort(newSort)
    }

    // Sync to URL if enabled
    urlState.setSortToURL(newSort)
  }, [currentSortBy, currentSortDirection, sortingConfig, urlState])

  // Ensure data is always an array
  const safeData = useMemo(() => Array.isArray(data) ? data : [], [data])

  // Apply client-side sorting if no server-side sorting
  const sortedData = useMemo(() => {
    if (sortingConfig?.serverSide || !currentSortBy) {
      return safeData
    }

    const column = columns.find(c => c.id === currentSortBy)
    if (!column) return safeData

    return [...safeData].sort((a, b) => {
      let valueA: any
      let valueB: any

      if (column.sortingFn) {
        return currentSortDirection === 'asc'
          ? column.sortingFn(a, b)
          : column.sortingFn(b, a)
      }

      if (column.accessorFn) {
        valueA = column.accessorFn(a)
        valueB = column.accessorFn(b)
      } else if (column.accessorKey) {
        // Handle nested keys like 'firm.name'
        const keys = column.accessorKey.split('.')
        valueA = keys.reduce((obj, key) => obj?.[key], a as any)
        valueB = keys.reduce((obj, key) => obj?.[key], b as any)
      } else {
        return 0
      }

      // Handle null/undefined
      if (valueA == null && valueB == null) return 0
      if (valueA == null) return currentSortDirection === 'asc' ? 1 : -1
      if (valueB == null) return currentSortDirection === 'asc' ? -1 : 1

      // Compare
      if (typeof valueA === 'string' && typeof valueB === 'string') {
        const comparison = valueA.localeCompare(valueB, undefined, { sensitivity: 'base' })
        return currentSortDirection === 'asc' ? comparison : -comparison
      }

      if (typeof valueA === 'number' && typeof valueB === 'number') {
        return currentSortDirection === 'asc' ? valueA - valueB : valueB - valueA
      }

      const comparison = String(valueA).localeCompare(String(valueB))
      return currentSortDirection === 'asc' ? comparison : -comparison
    })
  }, [safeData, columns, currentSortBy, currentSortDirection, sortingConfig?.serverSide])

  // Pagination hook
  const pagination = usePagination({
    totalCount: paginationConfig?.totalCount || sortedData.length,
    initialPageSize: paginationConfig?.pageSize || 25,
    initialPage: paginationConfig?.currentPage || (initialURLState?.page ?? 1),
    serverSide: paginationConfig?.serverSide || false,
    onPageChange: paginationConfig?.onPageChange,
  })

  // Selection hook - supports both controlled and uncontrolled modes
  const selection = useSelection({
    currentPageData: sortedData,
    totalCount: paginationConfig?.totalCount || sortedData.length,
    getRowId,
    onSelectionChange: selectionConfig?.onSelectionChange,
    onSelectAllPages: selectionConfig?.onSelectAllPages,
    // External controlled state
    externalSelectedIds: selectionConfig?.selectedIds,
    externalSelectAllPages: selectionConfig?.selectAllPages,
  })

  // Filters hook
  const filters = useFilters({
    initialFilters: filtersConfig?.value || (initialURLState?.filters ?? {}),
    onChange: filtersConfig?.onChange,
  })

  // Get current view state for saving
  const getCurrentViewState = useCallback((): Omit<SavedView, 'id' | 'name' | 'createdAt'> => {
    return {
      columnVisibility: columnVisibilityConfig?.enabled ? columnVisibility : undefined,
      columnOrder: columnReorderConfig?.enabled ? columnReorder.columnOrder : undefined,
      sortBy: currentSortBy,
      sortDirection: currentSortDirection,
      filters: filtersConfig?.enabled ? filters.filters : undefined,
      pageSize: paginationConfig?.pageSize,
    }
  }, [
    columnVisibility,
    columnVisibilityConfig?.enabled,
    columnReorder.columnOrder,
    columnReorderConfig?.enabled,
    currentSortBy,
    currentSortDirection,
    filters.filters,
    filtersConfig?.enabled,
    paginationConfig?.pageSize,
  ])

  // Keyboard navigation hook
  const keyboard = useTableKeyboard({
    data: sortedData,
    getRowId,
    selectedIds: selection.selectedIds,
    onToggleRow: selection.toggleRow,
    onToggleAll: selection.toggleAll,
    onRowClick,
    onDelete: bulkActions.find(action => action.id === 'delete')?.onClick
      ? (ids) => {
          const deleteAction = bulkActions.find(action => action.id === 'delete')
          if (deleteAction) {
            deleteAction.onClick(ids)
          }
        }
      : undefined,
    tableRef,
    enabled: true,
  })

  // Restore focus to search input after state-driven rerenders (e.g., URL sync)
  useEffect(() => {
    if (!searchConfig?.enabled || !searchConfig.preserveFocus) return
    if (!shouldRestoreFocusRef.current) return
    if (searchInputRef.current) {
      searchInputRef.current.focus()
      const len = searchConfig.value?.length ?? 0
      try {
        searchInputRef.current.setSelectionRange(len, len)
      } catch {
        // selection range may fail on some input types; ignore
      }
    }
    shouldRestoreFocusRef.current = false
  }, [searchConfig?.enabled, searchConfig?.preserveFocus, searchConfig?.value])

  // External selection state is now synced in useSelection hook

  // Sync pagination changes to URL
  useEffect(() => {
    if (!urlPersistenceConfig?.enabled) return
    if (!paginationConfig?.enabled) return

    urlState.setPageToURL(pagination.currentPage)
  }, [pagination.currentPage, urlPersistenceConfig?.enabled, paginationConfig?.enabled, urlState])

  // Sync filter changes to URL
  useEffect(() => {
    if (!urlPersistenceConfig?.enabled) return
    if (!filtersConfig?.enabled) return

    urlState.setFiltersToURL(filters.filters)
  }, [filters.filters, urlPersistenceConfig?.enabled, filtersConfig?.enabled, urlState])

  // Initialize search from URL on mount
  useEffect(() => {
    if (!urlPersistenceConfig?.enabled) return
    if (!searchConfig?.enabled) return
    if (!initialURLState?.search) return

    // Only set if search value is empty (first mount)
    if (!searchConfig.value && initialURLState.search) {
      searchConfig.onChange(initialURLState.search)
    }
  }, []) // Only run on mount

  // Check if all current page rows are selected
  const allRowsSelected = useMemo(() => {
    if (sortedData.length === 0) return false
    return sortedData.every(row => selection.selectedIds.has(getRowId(row)))
  }, [sortedData, selection.selectedIds, getRowId])

  // Prepare selected data for export
  const selectedDataForExport = useMemo(() => {
    if (!selectionConfig?.enabled || selection.selectedIds.size === 0) {
      return undefined
    }
    return sortedData.filter(row => selection.selectedIds.has(getRowId(row)))
  }, [sortedData, selection.selectedIds, getRowId, selectionConfig?.enabled])

  // Handle bulk action execution
  const handleExecuteBulkAction = async (action: typeof bulkActions[0]) => {
    const selectedIds = selection.selectAllPages
      ? new Set(sortedData.map(getRowId)) // In real implementation, this would fetch all IDs
      : selection.selectedIds

    // Show confirmation if needed
    if (action.confirmMessage) {
      const message = action.confirmMessage.replace('{count}', selectedIds.size.toString())
      if (!confirm(message)) {
        return
      }
    }

    // Check max selection
    if (action.maxSelection && selectedIds.size > action.maxSelection) {
      alert(`Maximum ${action.maxSelection} items can be selected for this action`)
      return
    }

    try {
      await action.onClick(selectedIds)
      // Clear selection after successful action
      selection.clearSelection()
    } catch (error) {
      console.error('Bulk action failed:', error)
    }
  }

  // Loading state
  if (loading && sortedData.length === 0) {
    return (
      <div className={cn('flex items-center justify-center p-12', className)}>
        <Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
      </div>
    )
  }

  // Empty state
  if (!loading && sortedData.length === 0 && emptyState) {
    return <div className={className}>{emptyState}</div>
  }

  return (
    <div ref={tableRef} className={cn('space-y-4', className)} tabIndex={0}>
      {/* Standard Table Toolbar */}
      <StandardTableToolbar
        searchEnabled={searchConfig?.enabled}
        searchPlaceholder={searchConfig?.placeholder}
        searchValue={searchConfig?.value}
        onSearchChange={(value) => {
          if (searchConfig) {
            shouldRestoreFocusRef.current = true
            searchConfig.onChange(value)
            urlState.setSearchToURL(value)
          }
        }}
        searchInputRef={searchInputRef}
        searchAutoFocus={searchConfig?.autoFocus}
        columnVisibilityEnabled={columnVisibilityConfig?.enabled}
        hideableColumns={hideableColumns}
        columnVisibility={columnVisibility}
        onToggleColumnVisibility={toggleColumnVisibility}
        exportEnabled={exportConfig?.enabled}
        exportData={sortedData}
        exportColumns={displayColumns}
        exportProps={exportConfig?.enabled ? {
          filteredData: sortedData.length < safeData.length ? sortedData : undefined,
          selectedData: selectedDataForExport,
          baseFilename: exportConfig.baseFilename,
          showProgress: exportConfig.showProgress,
          onExportStart: exportConfig.onExportStart,
          onExportComplete: exportConfig.onExportComplete,
          onExportError: exportConfig.onExportError,
        } : undefined}
        savedViewsEnabled={savedViewsConfig?.enabled}
        savedViews={savedViewsConfig?.views}
        currentViewId={savedViewsConfig?.currentViewId}
        savedViewsProps={savedViewsConfig?.enabled ? {
          onSaveView: savedViewsConfig.onSaveView,
          onUpdateView: savedViewsConfig.onUpdateView,
          onDeleteView: savedViewsConfig.onDeleteView,
          onLoadView: savedViewsConfig.onLoadView || (() => {}),
          getCurrentViewState,
        } : undefined}
      />

      {/* Filters */}
      {filtersConfig?.enabled && filtersConfig.config && (
        <TableFilters
          config={filtersConfig.config}
          filters={filters}
          defaultExpanded={filtersConfig?.defaultExpanded ?? false}
        />
      )}

      {/* Bulk Actions Bar */}
      {selectionConfig?.enabled && bulkActions.length > 0 && (
        <BulkActionBar
          selectedCount={selection.getSelectedCount()}
          selectAllPages={selection.selectAllPages}
          totalCount={paginationConfig?.totalCount || sortedData.length}
          bulkActions={bulkActions}
          onClearSelection={selection.clearSelection}
          onExecuteAction={handleExecuteBulkAction}
        />
      )}

      {/* Selection summary - only show when no bulk actions (BulkActionBar handles this otherwise) */}
      {selectionConfig?.enabled && selection.getSelectedCount() > 0 && bulkActions.length === 0 && (
        <div className="flex items-center justify-between text-sm text-muted-foreground">
          <div>
            {selection.selectAllPages ? (
              <span className="font-medium text-blue-600">
                All {paginationConfig?.totalCount || sortedData.length} items selected
              </span>
            ) : (
              <span>
                {selection.getSelectedCount()} item{selection.getSelectedCount() === 1 ? '' : 's'} selected{allRowsSelected ? ' on this page' : ''}
              </span>
            )}
          </div>

          {/* Show "Select All Pages" button if not all pages selected and there are multiple pages */}
          {!selection.selectAllPages &&
            allRowsSelected &&
            paginationConfig &&
            (paginationConfig.totalCount || 0) > sortedData.length && (
              <button
                onClick={selection.selectAllPagesToggle}
                className="text-blue-600 hover:text-blue-800 font-medium"
              >
                Select all {paginationConfig.totalCount} items
              </button>
            )}
        </div>
      )}

      {/* Select all pages option - shown below bulk action bar when applicable */}
      {selectionConfig?.enabled &&
        bulkActions.length > 0 &&
        !selection.selectAllPages &&
        allRowsSelected &&
        paginationConfig &&
        (paginationConfig.totalCount || 0) > sortedData.length && (
          <div className="flex items-center justify-center p-2 bg-blue-50 border border-blue-200 rounded-lg">
            <button
              onClick={selection.selectAllPagesToggle}
              className="text-blue-600 hover:text-blue-800 font-medium text-sm"
            >
              Select all {paginationConfig.totalCount} items across all pages
            </button>
          </div>
        )}

      {/* Data Table */}
      <DataTableCore
        data={sortedData}
        columns={displayColumns}
        getRowId={getRowId}
        selectionEnabled={selectionConfig?.enabled}
        selectedIds={selection.selectedIds}
        onToggleRow={selection.toggleRow}
        onToggleAll={selection.toggleAll}
        allRowsSelected={allRowsSelected}
        renderSelectionCell={selectionConfig?.renderSelectionCell}
        sortingEnabled={sortingEnabled}
        sortBy={currentSortBy}
        sortDirection={currentSortDirection}
        onSort={handleSort}
        columnReorderEnabled={columnReorderConfig?.enabled}
        onColumnDragEnd={columnReorder.handleDragEnd}
        columnResizeEnabled={columnResizeConfig?.enabled}
        columnWidths={columnResize.columnWidths}
        onColumnResizeStart={columnResize.startResize}
        isResizing={columnResize.isResizing}
        inlineEditEnabled={inlineEditConfig?.enabled}
        onCellEdit={inlineEditConfig?.onSave}
        rowActions={rowActions}
        onRowClick={onRowClick}
        loadingRows={loadingRows}
      />

      {/* Pagination */}
      {paginationConfig?.enabled && (
        <TablePagination
          pagination={pagination}
          totalFilteredCount={paginationConfig.totalCount}
        />
      )}
    </div>
  )
}
