'use client';

/**
 * UniversalListPage - 통합 리스트 페이지 컴포넌트
 *
 * 59개 리스트 페이지를 하나의 config 기반 컴포넌트로 통합
 * 기존 기능 100% 유지, 테이블 영역만 공통화
 *
 * 지원 모드:
 * - 서버 사이드 필터링/페이지네이션 (기본)
 * - 클라이언트 사이드 필터링/페이지네이션 (clientSideFiltering: true)
 */

import { useState, useEffect, useCallback, useMemo } from 'react';
import { useRouter, useParams } from 'next/navigation';
import { toast } from 'sonner';
import { DeleteConfirmDialog } from '@/components/ui/confirm-dialog';
import {
  IntegratedListTemplateV2,
  type PaginationConfig,
} from '@/components/templates/IntegratedListTemplateV2';
import type {
  UniversalListPageProps,
  TabOption,
  FilterValues,
} from './types';

export function UniversalListPage<T>({
  config,
  initialData,
  initialTotalCount,
  externalPagination,
  externalSelection,
  onTabChange,
  onSearchChange,
  onFilterChange: onFilterChangeCallback,
  externalIsLoading,
}: UniversalListPageProps<T>) {
  const router = useRouter();
  const params = useParams();
  const locale = (params.locale as string) || 'ko';

  // ===== 상태 관리 =====
  // 원본 데이터 (클라이언트 사이드 필터링용)
  const [rawData, setRawData] = useState<T[]>(initialData || []);
  // UI 상태
  const [currentPage, setCurrentPage] = useState(1);
  const [isLoading, setIsLoading] = useState(!initialData);
  const [searchValue, setSearchValue] = useState('');
  const [selectedItems, setSelectedItems] = useState<Set<string>>(new Set());
  // 탭이 없으면 IntegratedListTemplateV2의 기본값 'default'와 일치해야 함
  const [activeTab, setActiveTab] = useState(
    config.defaultTab || config.tabs?.[0]?.value || 'default'
  );
  const [filters, setFilters] = useState<Record<string, string | string[]>>(
    config.initialFilters || {}
  );
  const [tabs, setTabs] = useState<TabOption[]>(config.tabs || []);

  // 모달 상태 (detailMode === 'modal'일 때 사용)
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [selectedItem, setSelectedItem] = useState<T | null>(null);

  // 삭제 다이얼로그 상태
  const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
  const [itemToDelete, setItemToDelete] = useState<T | null>(null);
  const [isBulkDelete, setIsBulkDelete] = useState(false);

  const itemsPerPage = config.itemsPerPage || 20;

  // 모바일 인피니티 스크롤 로딩 상태 (서버 사이드 페이지네이션 시)
  const [isMobileLoading, setIsMobileLoading] = useState(false);

  // ===== ID 추출 헬퍼 =====
  const getItemId = useCallback(
    (item: T): string => {
      if (typeof config.idField === 'function') {
        return config.idField(item);
      }
      return String(item[config.idField]);
    },
    [config.idField]
  );

  // ===== 클라이언트 사이드 필터링 =====
  const filteredData = useMemo(() => {
    if (!config.clientSideFiltering) {
      return rawData;
    }

    let filtered = [...rawData];

    // 커스텀 필터 함수 (filterConfig 기반 복잡한 필터링)
    if (config.customFilterFn) {
      filtered = config.customFilterFn(filtered, filters);
    }

    // 탭 필터
    if (activeTab !== 'all' && config.tabFilter) {
      filtered = filtered.filter((item) => config.tabFilter!(item, activeTab));
    }

    // 검색 필터
    if (searchValue && config.searchFilter) {
      filtered = filtered.filter((item) =>
        config.searchFilter!(item, searchValue)
      );
    }

    // 커스텀 정렬 함수
    if (config.customSortFn) {
      filtered = config.customSortFn(filtered, filters);
    }

    return filtered;
  }, [rawData, activeTab, searchValue, filters, config.clientSideFiltering, config.tabFilter, config.searchFilter, config.customFilterFn, config.customSortFn]);

  // 클라이언트 사이드 페이지네이션
  const paginatedData = useMemo(() => {
    if (!config.clientSideFiltering) {
      return rawData;
    }
    const startIndex = (currentPage - 1) * itemsPerPage;
    return filteredData.slice(startIndex, startIndex + itemsPerPage);
  }, [config.clientSideFiltering, filteredData, currentPage, itemsPerPage, rawData]);

  // 총 개수 및 페이지 수
  const totalCount = config.clientSideFiltering ? filteredData.length : rawData.length;
  const totalPages = Math.ceil(totalCount / itemsPerPage);

  // 표시할 데이터
  const displayData = config.clientSideFiltering ? paginatedData : rawData;

  // ===== 탭 카운트 계산 (클라이언트 사이드) =====
  const computedTabs = useMemo(() => {
    if (!config.clientSideFiltering || !config.tabs || !config.tabFilter) {
      return tabs;
    }

    return config.tabs.map((tab) => {
      if (tab.value === 'all') {
        return { ...tab, count: rawData.length };
      }
      const count = rawData.filter((item) => config.tabFilter!(item, tab.value)).length;
      return { ...tab, count };
    });
  }, [config.clientSideFiltering, config.tabs, config.tabFilter, rawData, tabs]);

  // ===== 데이터 로딩 =====
  // isMobileAppend: 모바일 인피니티 스크롤로 추가 로드 시 true
  const fetchData = useCallback(async (isMobileAppend = false) => {
    // 모바일 추가 로드면 isMobileLoading, 그 외에는 isLoading
    if (isMobileAppend) {
      setIsMobileLoading(true);
    } else {
      setIsLoading(true);
    }

    try {
      const result = await config.actions.getList(
        config.clientSideFiltering
          ? { pageSize: 9999 } // 클라이언트 사이드: 전체 데이터 로드
          : {
              page: currentPage,
              pageSize: itemsPerPage,
              search: searchValue,
              filters,
              tab: activeTab,
            }
      );

      if (result.success && result.data) {
        setRawData(result.data);
      } else {
        toast.error(result.error || '데이터를 불러오는데 실패했습니다.');
      }
    } catch (error) {
      console.error('[UniversalListPage] Fetch error:', error);
      toast.error('데이터를 불러오는데 실패했습니다.');
    } finally {
      setIsLoading(false);
      setIsMobileLoading(false);
    }
  }, [config.actions, config.clientSideFiltering, currentPage, itemsPerPage, searchValue, filters, activeTab]);

  // 초기 로딩 (initialData가 없거나 빈 배열인 경우)
  useEffect(() => {
    if (!initialData || initialData.length === 0) {
      fetchData();
    }
  }, []);

  // initialData prop 변경 감지 (부모 컴포넌트에서 데이터 로드 후 전달하는 경우)
  useEffect(() => {
    if (initialData && initialData.length > 0) {
      setRawData(initialData);
    }
  }, [initialData]);

  // config.tabs 변경 감지 (동적 탭 카운트 업데이트용)
  useEffect(() => {
    if (config.tabs) {
      setTabs(config.tabs);
    }
  }, [config.tabs]);

  // 데이터 변경 콜백 (동적 컬럼 계산 등에 사용)
  // ⚠️ config.onDataChange를 deps에서 제외: 콜백 참조 변경으로 인한 무한 루프 방지
  useEffect(() => {
    config.onDataChange?.(rawData);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [rawData]);

  // 서버 사이드 필터링: 의존성 변경 시 데이터 새로고침
  // 이전 페이지를 추적하여 모바일 인피니티 스크롤 감지
  const [prevPage, setPrevPage] = useState(1);
  useEffect(() => {
    if (!config.clientSideFiltering && !isLoading && !isMobileLoading) {
      // 페이지가 증가하는 경우 = 모바일 인피니티 스크롤
      const isMobileAppend = currentPage > prevPage && currentPage > 1;
      fetchData(isMobileAppend);
      setPrevPage(currentPage);
    }
  }, [currentPage, searchValue, filters, activeTab]);

  // 동적 탭 로딩
  useEffect(() => {
    if (config.fetchTabs) {
      config.fetchTabs().then((fetchedTabs) => {
        setTabs(fetchedTabs);
        if (!activeTab || activeTab === 'all') {
          setActiveTab(fetchedTabs[0]?.value || 'all');
        }
      });
    }
  }, [config.fetchTabs]);

  // ===== 선택 핸들러 =====
  // 외부 선택 상태 사용 시 외부 핸들러 사용
  const effectiveSelectedItems = externalSelection?.selectedItems ?? selectedItems;
  const effectiveGetItemId = externalSelection?.getItemId ?? getItemId;

  const toggleSelection = useCallback(
    (id: string) => {
      if (externalSelection) {
        externalSelection.onToggleSelection(id);
      } else {
        setSelectedItems((prev) => {
          const newSet = new Set(prev);
          if (newSet.has(id)) {
            newSet.delete(id);
          } else {
            newSet.add(id);
          }
          return newSet;
        });
      }
    },
    [externalSelection]
  );

  const toggleSelectAll = useCallback(() => {
    if (externalSelection) {
      externalSelection.onToggleSelectAll();
    } else {
      const currentData = displayData;
      if (selectedItems.size === currentData.length && currentData.length > 0) {
        setSelectedItems(new Set());
      } else {
        const allIds = new Set(currentData.map((item) => getItemId(item)));
        setSelectedItems(allIds);
      }
    }
  }, [externalSelection, displayData, selectedItems.size, getItemId]);

  // ===== 행 클릭 핸들러 =====
  const handleRowClick = useCallback(
    (item: T) => {
      const id = getItemId(item);
      const detailMode = config.detailMode || 'page';

      if (detailMode === 'modal') {
        setSelectedItem(item);
        setIsModalOpen(true);
      } else if (detailMode === 'page') {
        router.push(`/${locale}${config.basePath}/${id}?mode=view`);
      }
    },
    [config.basePath, config.detailMode, getItemId, locale, router]
  );

  const handleEdit = useCallback(
    (item: T) => {
      const id = getItemId(item);
      router.push(`/${locale}${config.basePath}/${id}?mode=edit`);
    },
    [config.basePath, getItemId, locale, router]
  );

  const handleCreate = useCallback(() => {
    router.push(`/${locale}${config.basePath}?mode=new`);
  }, [config.basePath, locale, router]);

  // ===== 삭제 핸들러 =====
  const handleDeleteClick = useCallback((item: T) => {
    setItemToDelete(item);
    setIsBulkDelete(false);
    setDeleteDialogOpen(true);
  }, []);

  const handleBulkDeleteClick = useCallback(() => {
    if (effectiveSelectedItems.size === 0) {
      toast.warning('삭제할 항목을 선택해주세요.');
      return;
    }
    setIsBulkDelete(true);
    setDeleteDialogOpen(true);
  }, [effectiveSelectedItems.size]);

  const handleDeleteConfirm = useCallback(async () => {
    try {
      if (isBulkDelete) {
        if (config.actions.deleteBulk) {
          const result = await config.actions.deleteBulk(Array.from(effectiveSelectedItems));
          if (result.success) {
            toast.success(`${effectiveSelectedItems.size}건이 삭제되었습니다.`);
            // 클라이언트 사이드: 로컬 데이터에서 제거
            if (config.clientSideFiltering) {
              setRawData((prev) =>
                prev.filter((item) => !effectiveSelectedItems.has(getItemId(item)))
              );
            } else {
              fetchData();
            }
            if (!externalSelection) {
              setSelectedItems(new Set());
            }
          } else {
            toast.error(result.error || '삭제에 실패했습니다.');
          }
        } else if (config.actions?.deleteItem) {
          const ids = Array.from(effectiveSelectedItems);
          let successCount = 0;
          for (const id of ids) {
            const result = await config.actions.deleteItem(id);
            if (result.success) successCount++;
          }
          toast.success(`${successCount}건이 삭제되었습니다.`);
          if (config.clientSideFiltering) {
            setRawData((prev) =>
              prev.filter((item) => !effectiveSelectedItems.has(getItemId(item)))
            );
          } else {
            fetchData();
          }
          if (!externalSelection) {
            setSelectedItems(new Set());
          }
        }
      } else if (itemToDelete) {
        if (config.actions?.deleteItem) {
          const id = getItemId(itemToDelete);
          const result = await config.actions.deleteItem(id);
          if (result.success) {
            toast.success('삭제되었습니다.');
            if (config.clientSideFiltering) {
              setRawData((prev) => prev.filter((item) => getItemId(item) !== id));
            } else {
              fetchData();
            }
          } else {
            toast.error(result.error || '삭제에 실패했습니다.');
          }
        }
      }
    } catch (error) {
      console.error('[UniversalListPage] Delete error:', error);
      toast.error('삭제 중 오류가 발생했습니다.');
    } finally {
      setDeleteDialogOpen(false);
      setItemToDelete(null);
    }
  }, [config.actions, config.clientSideFiltering, externalSelection, fetchData, getItemId, isBulkDelete, itemToDelete, effectiveSelectedItems]);

  // ===== 검색 핸들러 =====
  const handleSearchChange = useCallback((value: string) => {
    setSearchValue(value);
    setCurrentPage(1);
    setSelectedItems(new Set());
    // 외부 콜백 호출 (서버 사이드 검색용)
    onSearchChange?.(value);
  }, [onSearchChange]);

  // ===== 필터 핸들러 =====
  const handleFilterChange = useCallback((key: string, value: string | string[]) => {
    const newFilters = { ...filters, [key]: value };
    setFilters(newFilters);
    setCurrentPage(1);
    setSelectedItems(new Set());
    // 외부 콜백 호출 (서버 사이드 필터링용)
    onFilterChangeCallback?.(newFilters);
  }, [filters, onFilterChangeCallback]);

  const handleFilterReset = useCallback(() => {
    setFilters(config.initialFilters || {});
    setCurrentPage(1);
    setSelectedItems(new Set());
  }, [config.initialFilters]);

  // ===== 탭 핸들러 =====
  const handleTabChange = useCallback((value: string) => {
    setActiveTab(value);
    setCurrentPage(1);
    setSelectedItems(new Set());
    // 외부 콜백 호출 (서버 사이드 필터링용)
    onTabChange?.(value);
  }, [onTabChange]);

  // ===== 페이지네이션 핸들러 =====
  const handlePageChange = useCallback((page: number) => {
    setCurrentPage(page);
    setSelectedItems(new Set());
  }, []);

  // ===== 통계 카드 계산 =====
  const computedStats = useMemo(() => {
    if (config.computeStats) {
      return config.computeStats(
        config.clientSideFiltering ? rawData : displayData,
        config.clientSideFiltering ? rawData.length : totalCount
      );
    }
    return config.stats;
  }, [config.computeStats, config.stats, config.clientSideFiltering, rawData, displayData, totalCount]);

  // ===== 필터 값 변환 =====
  const filterValuesObj: FilterValues = useMemo(() => {
    return filters as FilterValues;
  }, [filters]);

  // ===== 탭별 컬럼 선택 =====
  const effectiveColumns = useMemo(() => {
    if (config.columnsPerTab && activeTab && config.columnsPerTab[activeTab]) {
      return config.columnsPerTab[activeTab];
    }
    return config.columns;
  }, [config.columns, config.columnsPerTab, activeTab]);

  // ===== ID로 아이템 찾기 헬퍼 =====
  const getItemById = useCallback(
    (id: string): T | undefined => {
      return rawData.find((item) => getItemId(item) === id);
    },
    [rawData, getItemId]
  );

  // ===== 페이지네이션 config =====
  // 외부 페이지네이션 사용 시 외부 설정 사용
  const paginationConfig: PaginationConfig = useMemo(
    () => externalPagination ?? {
      currentPage,
      totalPages,
      totalItems: totalCount,
      itemsPerPage,
      onPageChange: handlePageChange,
    },
    [externalPagination, currentPage, totalPages, totalCount, itemsPerPage, handlePageChange]
  );

  // ===== 렌더링 함수 래퍼 =====
  const renderTableRow = useCallback(
    (item: T, index: number, globalIndex: number) => {
      const id = effectiveGetItemId(item);
      const isSelected = effectiveSelectedItems.has(id);
      return config.renderTableRow(item, index, globalIndex, {
        isSelected,
        onToggle: () => toggleSelection(id),
        onRowClick: () => handleRowClick(item),
        onEdit: () => handleEdit(item),
        onDelete: () => handleDeleteClick(item),
      });
    },
    [config, effectiveGetItemId, handleDeleteClick, handleEdit, handleRowClick, effectiveSelectedItems, toggleSelection]
  );

  const renderMobileCard = useCallback(
    (item: T, index: number, globalIndex: number, isSelected: boolean, onToggle: () => void) => {
      return config.renderMobileCard(item, index, globalIndex, {
        isSelected,
        onToggle,
        onRowClick: () => handleRowClick(item),
        onEdit: () => handleEdit(item),
        onDelete: () => handleDeleteClick(item),
      });
    },
    [config, handleDeleteClick, handleEdit, handleRowClick]
  );

  // ===== 삭제 확인 메시지 =====
  const deleteConfirmTitle = config.deleteConfirmMessage?.title || '삭제 확인';
  const deleteConfirmDescription =
    config.deleteConfirmMessage?.description ||
    (isBulkDelete
      ? `선택한 ${effectiveSelectedItems.size}건을 삭제하시겠습니까?`
      : '이 항목을 삭제하시겠습니까?');

  return (
    <>
      <IntegratedListTemplateV2<T>
        // 페이지 헤더
        title={config.title}
        description={config.description}
        icon={config.icon}
        headerActions={config.headerActions?.({
          onCreate: handleCreate,
          selectedItems: effectiveSelectedItems,
          onClearSelection: () => setSelectedItems(new Set()),
          onRefresh: fetchData,
        })}
        // 공통 헤더 옵션 (달력/등록버튼)
        dateRangeSelector={config.dateRangeSelector}
        createButton={config.createButton}
        // 탭 콘텐츠
        tabsContent={config.tabsContent}
        // 통계 카드
        stats={computedStats}
        // 경고 배너
        alertBanner={config.alertBanner}
        // 검색 및 필터
        searchValue={searchValue}
        onSearchChange={handleSearchChange}
        searchPlaceholder={config.searchPlaceholder}
        extraFilters={config.extraFilters}
        hideSearch={config.hideSearch}
        // 탭 (빈 배열일 때는 undefined로 전달해서 IntegratedListTemplateV2의 기본 탭 사용)
        tabs={computedTabs.length > 0 ? computedTabs : undefined}
        activeTab={activeTab}
        onTabChange={handleTabChange}
        // 필터 시스템
        filterConfig={config.filterConfig}
        filterValues={filterValuesObj}
        onFilterChange={handleFilterChange}
        onFilterReset={handleFilterReset}
        filterTitle={config.filterTitle}
        // 테이블 앞 콘텐츠 (함수일 경우 params 전달)
        beforeTableContent={
          typeof config.beforeTableContent === 'function'
            ? config.beforeTableContent({
                selectedItems: effectiveSelectedItems,
                onClearSelection: () => externalSelection ? undefined : setSelectedItems(new Set()),
              })
            : config.beforeTableContent
        }
        // 테이블 헤더 액션 (함수일 경우 params 전달)
        tableHeaderActions={
          typeof config.tableHeaderActions === 'function'
            ? config.tableHeaderActions({
                totalCount: externalPagination?.totalItems ?? totalCount,
                selectedItems: effectiveSelectedItems,
                onClearSelection: () => externalSelection ? undefined : setSelectedItems(new Set()),
              })
            : config.tableHeaderActions
        }
        // 테이블 컬럼 (탭별 다른 컬럼 지원)
        tableColumns={effectiveColumns}
        // 커스텀 테이블 헤더 (동적 컬럼용)
        renderCustomTableHeader={
          config.renderCustomTableHeader
            ? () =>
                config.renderCustomTableHeader!({
                  displayData,
                  selectedItems: effectiveSelectedItems,
                  onToggleSelectAll: toggleSelectAll,
                })
            : undefined
        }
        // 테이블 푸터
        tableFooter={config.tableFooter}
        // 데이터
        data={displayData}
        totalCount={totalCount}
        allData={config.clientSideFiltering ? filteredData : undefined}
        // 모바일 인피니티 스크롤 로딩 상태
        isMobileLoading={isMobileLoading}
        // 체크박스 선택
        selectedItems={effectiveSelectedItems}
        onToggleSelection={toggleSelection}
        onToggleSelectAll={toggleSelectAll}
        getItemId={effectiveGetItemId}
        onBulkDelete={config.actions?.deleteItem ? handleBulkDeleteClick : undefined}
        // 표시 옵션
        showCheckbox={config.showCheckbox}
        showRowNumber={config.showRowNumber}
        // 렌더링 함수
        renderTableRow={renderTableRow}
        renderMobileCard={renderMobileCard}
        // 페이지네이션
        pagination={paginationConfig}
        // 로딩 상태 (외부 로딩 상태 우선 사용)
        isLoading={externalIsLoading ?? isLoading}
      />

      {/* 삭제 확인 다이얼로그 */}
      <DeleteConfirmDialog
        open={deleteDialogOpen}
        onOpenChange={setDeleteDialogOpen}
        onConfirm={handleDeleteConfirm}
        title={deleteConfirmTitle}
        description={deleteConfirmDescription}
      />

      {/* 상세 모달 (detailMode === 'modal'일 때) */}
      {config.detailMode === 'modal' && config.DetailModalComponent && (
        <config.DetailModalComponent
          isOpen={isModalOpen}
          onClose={() => {
            setIsModalOpen(false);
            setSelectedItem(null);
          }}
          item={selectedItem}
          onRefresh={fetchData}
        />
      )}

      {/* 커스텀 다이얼로그 슬롯 */}
      {config.renderDialogs?.({
        data: displayData,
        selectedItems: effectiveSelectedItems,
        activeTab,
        onRefresh: fetchData,
        getItemById,
      })}
    </>
  );
}

// 타입 re-export
export * from './types';