/**
 * DataTable Component
 *
 * 범용 데이터 테이블 컴포넌트
 * - 검색/필터링
 * - 정렬
 * - 페이지네이션
 * - 행 선택
 * - 반응형 (데스크톱: 테이블, 모바일: 카드)
 *
 * @example
 * <DataTable
 *   data={items}
 *   columns={columns}
 *   search={{ placeholder: '검색...' }}
 *   pagination={{ pageSize: 20 }}
 *   selection={{ enabled: true }}
 *   rowActions={[
 *     { key: 'view', icon: Search, onClick: handleView },
 *     { key: 'edit', icon: Edit, onClick: handleEdit },
 *   ]}
 * />
 */

'use client';

import { useState, useMemo, useCallback } from 'react';
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@/components/ui/table';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Checkbox } from '@/components/ui/checkbox';
import { Button } from '@/components/ui/button';
import { Loader2, ArrowUpDown, ArrowUp, ArrowDown } from 'lucide-react';
import { cn } from '@/lib/utils';
import { Pagination } from './Pagination';
import { TabFilter } from './TabFilter';
import { SearchFilter } from './SearchFilter';
import type {
  DataTableProps,
  BaseDataItem,
  SortState,
  ColumnDef,
} from './types';

export function DataTable<T extends BaseDataItem>({
  data,
  columns,
  loading = false,

  // 검색/필터
  search,
  tabFilter,
  defaultFilterValue = 'all',

  // 선택
  selection,
  onSelectionChange,

  // 페이지네이션
  pagination = { pageSize: 20 },

  // 정렬
  defaultSort,
  onSortChange,

  // 액션
  rowActions = [],
  bulkActions = [],

  // 스타일
  striped = false,
  hoverable = true,

  // 빈 상태
  emptyState,

  // 기타
  onRowClick,
  getRowKey = (row) => row.id,
}: DataTableProps<T>) {
  // 상태
  const [searchTerm, setSearchTerm] = useState('');
  const [filterValue, setFilterValue] = useState(defaultFilterValue);
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
  const [currentPage, setCurrentPage] = useState(1);
  const [pageSize, setPageSize] = useState(pagination.pageSize);
  const [sort, setSort] = useState<SortState>(defaultSort || { column: null, direction: null });

  // 검색/필터/정렬 적용된 데이터
  const processedData = useMemo(() => {
    let result = [...data];

    // 탭 필터 적용
    if (tabFilter && filterValue !== 'all') {
      result = result.filter((item) => {
        const value = item[tabFilter.key];
        return value === filterValue;
      });
    }

    // 검색 적용
    if (search && searchTerm) {
      const searchLower = searchTerm.toLowerCase();
      const searchFields = search.searchFields || columns.map((c) => c.key);

      result = result.filter((item) =>
        searchFields.some((field) => {
          const value = item[field];
          if (value == null) return false;
          return String(value).toLowerCase().includes(searchLower);
        })
      );
    }

    // 정렬 적용
    if (sort.column && sort.direction) {
      result.sort((a, b) => {
        const aVal = a[sort.column!];
        const bVal = b[sort.column!];

        if (aVal == null && bVal == null) return 0;
        if (aVal == null) return 1;
        if (bVal == null) return -1;

        let comparison = 0;
        if (typeof aVal === 'number' && typeof bVal === 'number') {
          comparison = aVal - bVal;
        } else {
          comparison = String(aVal).localeCompare(String(bVal));
        }

        return sort.direction === 'desc' ? -comparison : comparison;
      });
    }

    return result;
  }, [data, tabFilter, filterValue, search, searchTerm, sort, columns]);

  // 페이지네이션 적용
  const totalPages = Math.ceil(processedData.length / pageSize);
  const startIndex = (currentPage - 1) * pageSize;
  const endIndex = startIndex + pageSize;
  const paginatedData = processedData.slice(startIndex, endIndex);

  // 전체 선택 상태
  const selectAll = useMemo(() => {
    if (paginatedData.length === 0) return false;
    return paginatedData.every((row) => selectedIds.has(getRowKey(row)));
  }, [paginatedData, selectedIds, getRowKey]);

  // 핸들러
  const handleSearchChange = useCallback((value: string) => {
    setSearchTerm(value);
    setCurrentPage(1);
  }, []);

  const handleFilterChange = useCallback((value: string) => {
    setFilterValue(value);
    setCurrentPage(1);
  }, []);

  const handleSort = useCallback((column: string) => {
    setSort((prev) => {
      let newDirection: SortState['direction'] = 'asc';
      if (prev.column === column) {
        if (prev.direction === 'asc') newDirection = 'desc';
        else if (prev.direction === 'desc') newDirection = null;
      }

      const newSort: SortState = {
        column: newDirection ? column : null,
        direction: newDirection,
      };

      onSortChange?.(newSort);
      return newSort;
    });
  }, [onSortChange]);

  const handleSelectAll = useCallback(() => {
    const newSelected = new Set(selectedIds);
    if (selectAll) {
      paginatedData.forEach((row) => newSelected.delete(getRowKey(row)));
    } else {
      paginatedData.forEach((row) => newSelected.add(getRowKey(row)));
    }
    setSelectedIds(newSelected);
    onSelectionChange?.(newSelected);
  }, [selectAll, paginatedData, selectedIds, getRowKey, onSelectionChange]);

  const handleSelectRow = useCallback((row: T) => {
    const key = getRowKey(row);
    const newSelected = new Set(selectedIds);

    if (selection?.single) {
      newSelected.clear();
      if (!selectedIds.has(key)) {
        newSelected.add(key);
      }
    } else {
      if (newSelected.has(key)) {
        newSelected.delete(key);
      } else {
        newSelected.add(key);
      }
    }

    setSelectedIds(newSelected);
    onSelectionChange?.(newSelected);
  }, [selectedIds, selection, getRowKey, onSelectionChange]);

  const handlePageSizeChange = useCallback((size: number) => {
    setPageSize(size);
    setCurrentPage(1);
  }, []);

  // 정렬 아이콘 렌더링
  const renderSortIcon = (column: ColumnDef<T>) => {
    if (!column.sortable) return null;

    if (sort.column !== column.key) {
      return <ArrowUpDown className="ml-1 h-4 w-4 opacity-50" />;
    }
    if (sort.direction === 'asc') {
      return <ArrowUp className="ml-1 h-4 w-4" />;
    }
    if (sort.direction === 'desc') {
      return <ArrowDown className="ml-1 h-4 w-4" />;
    }
    return <ArrowUpDown className="ml-1 h-4 w-4 opacity-50" />;
  };

  // 빈 상태 렌더링
  const renderEmptyState = () => {
    const isFiltered = searchTerm || filterValue !== 'all';
    const title = isFiltered
      ? emptyState?.filteredTitle || '검색 결과가 없습니다.'
      : emptyState?.title || '데이터가 없습니다.';
    const description = isFiltered
      ? emptyState?.filteredDescription
      : emptyState?.description;

    return (
      <div className="text-center py-12 text-muted-foreground">
        {emptyState?.icon && (
          <emptyState.icon className="w-12 h-12 mx-auto mb-4 opacity-50" />
        )}
        <p className="text-lg font-medium">{title}</p>
        {description && <p className="text-sm mt-1">{description}</p>}
      </div>
    );
  };

  // 선택된 항목들
  const selectedItems = useMemo(() => {
    return data.filter((item) => selectedIds.has(getRowKey(item)));
  }, [data, selectedIds, getRowKey]);

  // 필터 옵션에 카운트 추가
  const filterOptionsWithCount = useMemo(() => {
    if (!tabFilter) return [];
    return tabFilter.options.map((opt) => ({
      ...opt,
      count: opt.value === 'all'
        ? data.length
        : data.filter((item) => item[tabFilter.key] === opt.value).length,
    }));
  }, [tabFilter, data]);

  return (
    <div className="space-y-4">
      {/* 검색/필터 */}
      {(search || tabFilter) && (
        <Card>
          <CardContent className="p-4 md:p-6">
            <SearchFilter
              searchValue={searchTerm}
              onSearchChange={handleSearchChange}
              searchConfig={search}
              filterValue={filterValue}
              onFilterChange={tabFilter ? handleFilterChange : undefined}
              filterOptions={filterOptionsWithCount}
            />
          </CardContent>
        </Card>
      )}

      {/* 벌크 액션 */}
      {bulkActions.length > 0 && selectedIds.size > 0 && (
        <Card>
          <CardContent className="p-3 flex items-center gap-2">
            <span className="text-sm text-muted-foreground">
              {selectedIds.size}개 선택됨
            </span>
            <div className="flex-1" />
            {bulkActions
              .filter((action) => !action.minSelected || selectedIds.size >= action.minSelected)
              .map((action) => (
                <Button
                  key={action.key}
                  variant={action.variant || 'outline'}
                  size="sm"
                  onClick={() => action.onClick(selectedItems)}
                >
                  {action.icon && <action.icon className="w-4 h-4 mr-1" />}
                  {action.label}
                </Button>
              ))}
          </CardContent>
        </Card>
      )}

      {/* 메인 테이블 카드 */}
      <Card>
        <CardHeader>
          <CardTitle className="text-sm md:text-base">
            {tabFilter
              ? `${filterOptionsWithCount.find((o) => o.value === filterValue)?.label || ''} 목록`
              : '전체 목록'}{' '}
            ({processedData.length}개)
          </CardTitle>
        </CardHeader>
        <CardContent className="p-4 md:p-6">
          {/* 탭 필터 */}
          {tabFilter && (
            <div className="mb-6">
              <TabFilter
                value={filterValue}
                onChange={handleFilterChange}
                options={filterOptionsWithCount}
              />
            </div>
          )}

          {/* 로딩 상태 */}
          {loading ? (
            <div className="flex items-center justify-center py-12">
              <Loader2 className="w-8 h-8 animate-spin text-primary" />
              <span className="ml-3 text-muted-foreground">로딩 중...</span>
            </div>
          ) : paginatedData.length === 0 ? (
            renderEmptyState()
          ) : (
            <>
              {/* 모바일 카드 뷰 */}
              <div className="lg:hidden space-y-3">
                {paginatedData.map((row, index) => (
                  <div
                    key={getRowKey(row)}
                    className={cn(
                      'border rounded-lg p-4 space-y-3 bg-card transition-colors',
                      hoverable && 'hover:bg-muted/50',
                      onRowClick && 'cursor-pointer'
                    )}
                    onClick={() => onRowClick?.(row)}
                  >
                    <div className="flex items-start justify-between gap-3">
                      {selection?.enabled && (
                        <Checkbox
                          checked={selectedIds.has(getRowKey(row))}
                          onCheckedChange={() => handleSelectRow(row)}
                          onClick={(e) => e.stopPropagation()}
                        />
                      )}
                      <div className="flex-1 space-y-2">
                        {columns
                          .filter((col) => col.renderMobile !== null)
                          .map((col) => {
                            const value = row[col.key];
                            const rendered = col.renderMobile
                              ? col.renderMobile(value, row, index)
                              : col.render
                              ? col.render(value, row, index)
                              : value;
                            if (rendered === null || rendered === undefined) return null;
                            return (
                              <div key={col.key}>
                                {rendered as React.ReactNode}
                              </div>
                            );
                          })}
                      </div>
                    </div>
                    {rowActions.length > 0 && (
                      <div className="flex items-center justify-end gap-1 pt-2 border-t">
                        {rowActions
                          .filter((action) => !action.visible || action.visible(row))
                          .map((action) => (
                            <Button
                              key={action.key}
                              variant={action.variant || 'ghost'}
                              size="sm"
                              onClick={(e) => {
                                e.stopPropagation();
                                action.onClick(row);
                              }}
                              title={action.tooltip}
                              className="h-8 px-3"
                            >
                              {action.icon && <action.icon className="h-4 w-4" />}
                              {action.label && (
                                <span className="ml-1 text-xs">{action.label}</span>
                              )}
                            </Button>
                          ))}
                      </div>
                    )}
                  </div>
                ))}
              </div>

              {/* 데스크톱 테이블 */}
              <div className="hidden lg:block rounded-md border">
                <Table>
                  <TableHeader>
                    <TableRow>
                      {selection?.enabled && (
                        <TableHead className="w-[50px]">
                          {!selection.single && (
                            <Checkbox
                              checked={selectAll}
                              onCheckedChange={handleSelectAll}
                            />
                          )}
                        </TableHead>
                      )}
                      {columns
                        .filter((col) => !col.hideOnMobile || !col.hideOnTablet)
                        .map((col) => (
                          <TableHead
                            key={col.key}
                            className={cn(
                              col.width && `w-[${col.width}]`,
                              col.minWidth && `min-w-[${col.minWidth}]`,
                              col.hideOnMobile && 'hidden md:table-cell',
                              col.hideOnTablet && 'hidden lg:table-cell',
                              col.sortable && 'cursor-pointer select-none',
                              col.align === 'center' && 'text-center',
                              col.align === 'right' && 'text-right'
                            )}
                            onClick={() => col.sortable && handleSort(col.key)}
                          >
                            <div className={cn(
                              'flex items-center',
                              col.align === 'center' && 'justify-center',
                              col.align === 'right' && 'justify-end'
                            )}>
                              {col.header}
                              {renderSortIcon(col)}
                            </div>
                          </TableHead>
                        ))}
                      {rowActions.length > 0 && (
                        <TableHead className="text-right min-w-[100px]">작업</TableHead>
                      )}
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {paginatedData.map((row, index) => (
                      <TableRow
                        key={getRowKey(row)}
                        className={cn(
                          hoverable && 'hover:bg-muted/50',
                          striped && index % 2 === 1 && 'bg-muted/25',
                          onRowClick && 'cursor-pointer'
                        )}
                        onClick={() => onRowClick?.(row)}
                      >
                        {selection?.enabled && (
                          <TableCell>
                            <Checkbox
                              checked={selectedIds.has(getRowKey(row))}
                              onCheckedChange={() => handleSelectRow(row)}
                              onClick={(e) => e.stopPropagation()}
                            />
                          </TableCell>
                        )}
                        {columns
                          .filter((col) => !col.hideOnMobile || !col.hideOnTablet)
                          .map((col) => {
                            const value = row[col.key];
                            return (
                              <TableCell
                                key={col.key}
                                className={cn(
                                  col.hideOnMobile && 'hidden md:table-cell',
                                  col.hideOnTablet && 'hidden lg:table-cell',
                                  col.align === 'center' && 'text-center',
                                  col.align === 'right' && 'text-right'
                                )}
                              >
                                {col.render ? col.render(value, row, index) : String(value ?? '-')}
                              </TableCell>
                            );
                          })}
                        {rowActions.length > 0 && (
                          <TableCell className="text-right">
                            <div className="flex items-center justify-end gap-1">
                              {rowActions
                                .filter((action) => !action.visible || action.visible(row))
                                .map((action) => (
                                  <Button
                                    key={action.key}
                                    variant={action.variant || 'ghost'}
                                    size="sm"
                                    onClick={(e) => {
                                      e.stopPropagation();
                                      action.onClick(row);
                                    }}
                                    title={action.tooltip || action.label}
                                  >
                                    {action.icon && <action.icon className="w-4 h-4" />}
                                  </Button>
                                ))}
                            </div>
                          </TableCell>
                        )}
                      </TableRow>
                    ))}
                  </TableBody>
                </Table>
              </div>

              {/* 페이지네이션 */}
              <Pagination
                currentPage={currentPage}
                totalPages={totalPages}
                totalItems={processedData.length}
                startIndex={startIndex}
                endIndex={endIndex}
                onPageChange={setCurrentPage}
                pageSize={pageSize}
                onPageSizeChange={pagination.showPageSizeSelector ? handlePageSizeChange : undefined}
                pageSizeOptions={pagination.pageSizeOptions}
              />
            </>
          )}
        </CardContent>
      </Card>
    </div>
  );
}

export default DataTable;