import { useCallback, useMemo, useState, type ReactNode } from 'react'
import {
  useTable,
  type PaginationState,
  type RowSelectionState,
  type SortingState,
} from '@tanstack/react-table'
import { CircleAlertIcon, FilterIcon, FilterXIcon } from 'lucide-react'

import { CountedLineTabs } from '@/components/counted-line-tabs'
import { Badge } from '@/components/reui/badge'
import { DataGrid, DataGridContainer, dataGridFeatures } from '@/components/reui/data-grid/data-grid'
import { DataGridPagination } from '@/components/reui/data-grid/data-grid-pagination'
import { DataGridTable } from '@/components/reui/data-grid/data-grid-table'
import {
  Filters,
  type Filter,
  type FilterFieldConfig,
} from '@/components/reui/filters'
import {
  Frame,
  FrameDescription,
  FrameFooter,
  FrameHeader,
  FramePanel,
  FrameTitle,
} from '@/components/reui/frame'
import { Button } from '@cfdm/ui/components/button'
import { Separator } from '@cfdm/ui/components/separator'
import { Skeleton } from '@cfdm/ui/components/skeleton'
import {
  Alert,
  AlertDescription,
  AlertTitle,
} from '@/components/reui/alert'
import { EmptyState } from '@/components/empty-state'
import { applyFiltersToData } from './filter-utils'
import {
  FrameDataGrid,
  kitDataGridTableLayout,
  type DataGridColumnDef,
  type FrameDataGridProps,
} from './frame-data-grid'

export interface ResourcePageTab {
  id: string
  label: string
  count?: number
}

type SimpleGridPassthrough<T extends object> = Pick<
  FrameDataGridProps<T>,
  | 'onRowClick'
  | 'pagination'
  | 'footerContent'
  | 'dense'
  | 'initialSorting'
  | 'virtualization'
  | 'height'
  | 'onRowSelectionChange'
  | 'enableColumnVisibility'
  | 'columnVisibility'
  | 'onColumnVisibilityChange'
  | 'columnVisibilityTrigger'
  | 'columnVisibilityStorageKey'
  | 'initialColumnVisibility'
  | 'className'
  | 'tableWidth'
  | 'horizontalScroll'
  | 'pinLeftColumnIds'
  | 'columnPinControls'
>

export interface ResourcePageProps<T extends object> extends SimpleGridPassthrough<T> {
  /** Optional when hideHeader / embedded under PageHeader. */
  title?: string
  description?: string
  tabs?: ResourcePageTab[]
  activeTab?: string
  onTabChange?: (tabId: string) => void
  tabFilter?: (item: T, tabId: string) => boolean
  /** Empty / omit → simple Frame grid (no ReUI Filters). Preview: data-grid-filtering-2 */
  filterFields?: FilterFieldConfig[]
  filters?: Filter[]
  onFiltersChange?: (filters: Filter[]) => void
  onClearFilters?: () => void
  getFilterFieldValue?: (item: T, field: string) => unknown
  columns: DataGridColumnDef<T>[]
  data: T[]
  getRowId: (row: T, index?: number) => string
  isLoading?: boolean
  isError?: boolean
  error?: Error | null
  onRetry?: () => void
  primaryAction?: ReactNode
  emptyState?: { title: string; description?: string; action?: ReactNode }
  pageSize?: number
  enableRowSelection?: boolean
  selectionToolbar?: (ctx: {
    selectedIds: string[]
    selectedCount: number
    clearSelection: () => void
  }) => ReactNode
  toolbarExtra?: ReactNode
  hideHeader?: boolean
  pinLastColumn?: boolean
  /** FrameDataGrid aliases when used as simple list. */
  emptyTitle?: string
  emptyDescription?: string
  emptyAction?: ReactNode
  /** Alias for primaryAction (FrameDataGrid `actions`). */
  actions?: ReactNode
}

function ResourcePageSkeleton() {
  return (
    <Frame dense variant="default" spacing="sm" className="w-full">
      <FrameHeader>
        <Skeleton className="h-5 w-48" />
        <Skeleton className="mt-1 h-4 w-72" />
      </FrameHeader>
      <FramePanel className="p-0">
        <div className="flex flex-col gap-3 p-4">
          <Skeleton className="h-9 w-full max-w-md" />
          {Array.from({ length: 6 }).map((_, i) => (
            <Skeleton key={i} className="h-10 w-full" />
          ))}
        </div>
      </FramePanel>
    </Frame>
  )
}

function ResourceLoadError({
  error,
  onRetry,
}: {
  error?: Error | null
  onRetry?: () => void
}) {
  return (
    <Alert variant="destructive">
      <CircleAlertIcon />
      <AlertTitle>Ошибка загрузки</AlertTitle>
      <AlertDescription className="flex flex-col gap-2">
        <span>{error?.message ?? 'Не удалось загрузить данные'}</span>
        {onRetry ? (
          <Button type="button" variant="outline" size="sm" onClick={onRetry}>
            Повторить
          </Button>
        ) : null}
      </AlertDescription>
    </Alert>
  )
}

const noopFiltersChange = (_filters: Filter[]) => {}
const defaultGetFilterFieldValue = (_item: unknown, _field: string) => undefined

function ResourcePageSimple<T extends object>({
  title = '',
  description,
  columns,
  data,
  getRowId,
  isLoading = false,
  isError = false,
  error = null,
  onRetry,
  primaryAction,
  actions,
  emptyState,
  emptyTitle,
  emptyDescription,
  emptyAction,
  pageSize = 10,
  enableRowSelection = false,
  toolbarExtra,
  hideHeader = false,
  pinLastColumn = false,
  onRowClick,
  pagination,
  footerContent,
  dense,
  initialSorting,
  virtualization,
  height,
  onRowSelectionChange,
  enableColumnVisibility,
  columnVisibility,
  onColumnVisibilityChange,
  columnVisibilityTrigger,
  columnVisibilityStorageKey,
  initialColumnVisibility,
  className,
  tableWidth,
  horizontalScroll,
  pinLeftColumnIds,
  columnPinControls,
}: ResourcePageProps<T>) {
  if (isLoading) return <ResourcePageSkeleton />
  if (isError) return <ResourceLoadError error={error} onRetry={onRetry} />

  const headerActions = primaryAction ?? actions
  const resolvedEmpty = emptyState ?? (
    emptyTitle || emptyDescription || emptyAction
      ? { title: emptyTitle ?? 'Нет записей', description: emptyDescription, action: emptyAction }
      : undefined
  )

  return (
    <div className="w-full">
      {toolbarExtra ? (
        <div className="mb-3 flex flex-wrap items-center gap-2">{toolbarExtra}</div>
      ) : null}
      <FrameDataGrid
        title={hideHeader ? undefined : title || undefined}
        description={hideHeader ? undefined : description}
        actions={hideHeader ? undefined : headerActions}
        columns={columns}
        data={data}
        rowId={getRowId}
        emptyTitle={resolvedEmpty?.title}
        emptyDescription={resolvedEmpty?.description}
        emptyAction={resolvedEmpty?.action}
        pinLastColumn={pinLastColumn}
        pageSize={pageSize}
        enableRowSelection={enableRowSelection}
        onRowClick={onRowClick}
        pagination={pagination}
        footerContent={footerContent}
        dense={dense}
        initialSorting={initialSorting}
        virtualization={virtualization}
        height={height}
        onRowSelectionChange={onRowSelectionChange}
        enableColumnVisibility={enableColumnVisibility}
        columnVisibility={columnVisibility}
        onColumnVisibilityChange={onColumnVisibilityChange}
        columnVisibilityTrigger={columnVisibilityTrigger}
        columnVisibilityStorageKey={columnVisibilityStorageKey}
        initialColumnVisibility={initialColumnVisibility}
        className={className}
        tableWidth={tableWidth}
        horizontalScroll={horizontalScroll}
        pinLeftColumnIds={pinLeftColumnIds}
        columnPinControls={columnPinControls}
      />
    </div>
  )
}

function ResourcePageFiltered<T extends object>({
  title = '',
  description,
  tabs,
  activeTab: controlledTab,
  onTabChange,
  tabFilter,
  filterFields = [],
  filters = [],
  onFiltersChange = noopFiltersChange,
  onClearFilters,
  getFilterFieldValue = defaultGetFilterFieldValue as (item: T, field: string) => unknown,
  columns,
  data,
  getRowId,
  isLoading = false,
  isError = false,
  error = null,
  onRetry,
  primaryAction,
  actions,
  emptyState,
  pageSize = 10,
  enableRowSelection = false,
  selectionToolbar,
  toolbarExtra,
  hideHeader = false,
  pinLastColumn = false,
  enableColumnVisibility = false,
}: ResourcePageProps<T>) {
  const headerActions = primaryAction ?? actions
  const [internalTab, setInternalTab] = useState(tabs?.[0]?.id ?? 'all')
  const activeTab = controlledTab ?? internalTab
  const showFilters = filterFields.length > 0

  const [sorting, setSorting] = useState<SortingState>([])
  const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
  const [pagination, setPagination] = useState<PaginationState>({
    pageIndex: 0,
    pageSize,
  })

  const resetPagination = useCallback(() => {
    setPagination((current) =>
      current.pageIndex === 0 ? current : { ...current, pageIndex: 0 },
    )
  }, [])

  const filteredData = useMemo(() => {
    let result = showFilters
      ? applyFiltersToData(data, filters, getFilterFieldValue)
      : data
    if (tabs && tabs.length > 0 && tabFilter && activeTab !== 'all') {
      result = result.filter((item) => tabFilter(item, activeTab))
    }
    return result
  }, [data, filters, getFilterFieldValue, tabs, tabFilter, activeTab, showFilters])

  const tabCounts = useMemo(() => {
    if (!tabs?.length || !tabFilter) return {}
    const base = showFilters
      ? applyFiltersToData(data, filters, getFilterFieldValue)
      : data
    const counts: Record<string, number> = {}
    for (const tab of tabs) {
      counts[tab.id] =
        tab.id === 'all'
          ? base.length
          : base.filter((item) => tabFilter(item, tab.id)).length
    }
    return counts
  }, [tabs, tabFilter, data, filters, getFilterFieldValue, showFilters])

  const selectedIds = useMemo(
    () => Object.keys(rowSelection).filter((id) => rowSelection[id]),
    [rowSelection],
  )

  const selectedCount = selectedIds.length

  const lastColId = pinLastColumn ? (columns[columns.length - 1]?.id ?? '') : ''
  const enablePinning = Boolean(pinLastColumn && lastColId)
  const columnPinning = {
    start: [] as string[],
    end: enablePinning ? [lastColId] : [],
  }

  const clearSelection = useCallback(() => {
    setRowSelection({})
  }, [])

  const table = useTable({
    features: dataGridFeatures,
    data: filteredData,
    columns,
    getRowId: (row) => getRowId(row),
    state: {
      sorting,
      rowSelection,
      pagination,
      ...(enablePinning ? { columnPinning } : {}),
    },
    initialState: enablePinning ? { columnPinning } : undefined,
    enableRowSelection,
    onSortingChange: setSorting,
    onRowSelectionChange: setRowSelection,
    onPaginationChange: setPagination,
  })

  const handleTabChange = useCallback(
    (value: string) => {
      if (onTabChange) onTabChange(value)
      else setInternalTab(value)
      resetPagination()
    },
    [onTabChange, resetPagination],
  )

  const handleFiltersChange = useCallback(
    (next: Filter[]) => {
      onFiltersChange(next)
      resetPagination()
    },
    [onFiltersChange, resetPagination],
  )

  const handleClear = useCallback(() => {
    onClearFilters?.()
    resetPagination()
  }, [onClearFilters, resetPagination])

  const countedTabs = useMemo(
    () =>
      (tabs ?? []).map((tab) => ({
        id: tab.id,
        label: tab.label,
        count: tabCounts[tab.id] ?? tab.count ?? 0,
      })),
    [tabs, tabCounts],
  )

  if (isLoading) return <ResourcePageSkeleton />
  if (isError) return <ResourceLoadError error={error} onRetry={onRetry} />

  if (data.length === 0 && emptyState) {
    return (
      <Frame dense spacing="sm" className="w-full">
        <FramePanel className="flex min-h-[min(28rem,55svh)] w-full flex-col items-center justify-center p-0">
          <EmptyState
            title={emptyState.title}
            description={emptyState.description}
            action={emptyState.action}
          />
        </FramePanel>
      </Frame>
    )
  }

  return (
    <div className="w-full">
      {selectionToolbar && selectedCount > 0
        ? selectionToolbar({
            selectedIds,
            selectedCount,
            clearSelection,
          })
        : null}
      <DataGrid
        table={table}
        recordCount={filteredData.length}
        emptyMessage="Нет записей по выбранным фильтрам."
        tableLayout={kitDataGridTableLayout({
          dense: true,
          width: 'fixed',
          columnsPinnable: enablePinning,
          columnsVisibility: enableColumnVisibility,
        })}
      >
        <Frame dense variant="default" spacing="sm" className="w-full">
          {!hideHeader ? (
            <FrameHeader className="flex-row items-start justify-between gap-3">
              <div className="flex min-w-0 flex-col gap-px">
                <FrameTitle className="text-balance">{title}</FrameTitle>
                {description ? (
                  <FrameDescription className="flex flex-wrap items-center gap-1.5 text-xs text-pretty">
                    <span>{description}</span>
                    <span
                      className="bg-input size-1 shrink-0 rounded-full"
                      aria-hidden="true"
                    />
                    <span className="tabular-nums">
                      {filteredData.length} записей
                    </span>
                    {selectedCount > 0 ? (
                      <>
                        <span
                          className="bg-input size-1 shrink-0 rounded-full"
                          aria-hidden="true"
                        />
                        <span>{selectedCount} выбрано</span>
                      </>
                    ) : null}
                  </FrameDescription>
                ) : null}
              </div>
              {headerActions ? (
                <div className="flex shrink-0 flex-wrap items-center justify-end gap-2">
                  {headerActions}
                </div>
              ) : null}
            </FrameHeader>
          ) : null}

          <FramePanel className="p-0 shadow-none!">
            {countedTabs.length > 0 ? (
              <>
                <div className="px-(--frame-panel-header-px) pt-(--frame-panel-header-py)">
                  <CountedLineTabs
                    tabs={countedTabs}
                    value={activeTab}
                    onValueChange={handleTabChange}
                  />
                </div>
                <Separator />
              </>
            ) : null}

            <div className="flex flex-wrap items-center justify-between gap-3 px-(--frame-panel-header-px) py-(--frame-panel-header-py)">
              {showFilters ? (
                <Filters
                  filters={filters}
                  fields={filterFields}
                  onChange={handleFiltersChange}
                  size="default"
                  trigger={
                    <Button type="button" variant="outline" aria-label="Фильтры">
                      <FilterIcon className="size-4" aria-hidden="true" />
                      Фильтры
                    </Button>
                  }
                />
              ) : (
                <div />
              )}
              <div className="flex flex-wrap items-center justify-end gap-2">
                {toolbarExtra}
                {selectedCount > 0 ? (
                  <Badge size="sm" variant="secondary">
                    {selectedCount} выбрано
                  </Badge>
                ) : null}
                {showFilters && onClearFilters ? (
                  <Button type="button" variant="outline" onClick={handleClear}>
                    <FilterXIcon className="size-4" aria-hidden="true" />
                    Сбросить
                  </Button>
                ) : null}
              </div>
            </div>

            {(showFilters || toolbarExtra || selectedCount > 0) ? <Separator /> : null}

            <DataGridContainer border={false}>
              <DataGridTable />
            </DataGridContainer>

            <Separator />

            <FrameFooter>
              <DataGridPagination
                sizes={[5, 10, 20, 50]}
                rowsPerPageLabel="Строк на странице"
                info="{from}–{to} из {count}"
                previousPageLabel="Предыдущая"
                nextPageLabel="Следующая"
              />
            </FrameFooter>
          </FramePanel>
        </Frame>
      </DataGrid>
    </div>
  )
}

/**
 * Ops list page: Frame + DataGrid (+ optional ReUI Filters / tabs).
 * Without filterFields/tabs → simple CRUD grid (FrameDataGrid under the hood).
 * Preview: https://reui.io/preview/base/data-grid-filtering-2
 */
export function ResourcePage<T extends object>(props: ResourcePageProps<T>) {
  const showFilters = (props.filterFields?.length ?? 0) > 0
  const hasTabs = (props.tabs?.length ?? 0) > 0
  if (!showFilters && !hasTabs) {
    return <ResourcePageSimple {...props} />
  }
  return <ResourcePageFiltered {...props} />
}
