'use client';

/**
 * 지출 예상 내역서 - UniversalListPage 마이그레이션
 *
 * 기존 IntegratedListTemplateV2 → UniversalListPage config 기반으로 변환
 * - 월별 그룹핑 테이블 (헤더, 소계, 합계 행 포함)
 * - 등록/수정 폼 다이얼로그
 * - 예상 지급일 변경 다이얼로그
 * - 일괄 삭제 다이얼로그
 * - 외부 선택 상태 관리 (데이터 행만 선택 가능)
 */

import { useState, useMemo, useCallback, useTransition, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { format } from 'date-fns';
import { toast } from 'sonner';
import {
  Receipt,
  Calendar as CalendarIcon,
  FileText,
  Plus,
  Pencil,
  Trash2,
} from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Badge } from '@/components/ui/badge';
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import { Calendar } from '@/components/ui/calendar';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { TableRow, TableCell } from '@/components/ui/table';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import {
  UniversalListPage,
  type UniversalListConfig,
  type SelectionHandlers,
  type RowClickHandlers,
  type StatCard,
} from '@/components/templates/UniversalListPage';
import { ListMobileCard, InfoField } from '@/components/organisms/MobileCard';
import type {
  ExpectedExpenseRecord,
  TransactionType,
  PaymentStatus,
  ApprovalStatus,
  SortOption,
} from './types';
import {
  TRANSACTION_TYPE_LABELS,
  PAYMENT_STATUS_LABELS,
  APPROVAL_STATUS_LABELS,
  SORT_OPTIONS,
} from './types';
import {
  deleteExpectedExpense,
  deleteExpectedExpenses,
  updateExpectedPaymentDate,
  createExpectedExpense,
  updateExpectedExpense,
  getClients,
  getBankAccounts,
} from './actions';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { CurrencyInput } from '@/components/ui/currency-input';
import {
  TRANSACTION_TYPE_FILTER_OPTIONS,
  PAYMENT_STATUS_FILTER_OPTIONS,
  ACCOUNT_SUBJECT_OPTIONS,
} from './types';

// ===== 테이블 행 타입 (데이터 + 그룹 헤더 + 소계) =====
type RowType = 'data' | 'monthHeader' | 'monthSubtotal' | 'totalExpense' | 'expectedBalance' | 'finalBalance';

interface TableRowData extends ExpectedExpenseRecord {
  rowType: RowType;
  monthLabel?: string;
  subtotalAmount?: number;
  dataIndex?: number; // 데이터 행 순번 (헤더/소계 제외)
}

// ===== 컴포넌트 Props =====
interface ExpectedExpenseManagementProps {
  initialData: ExpectedExpenseRecord[];
  pagination: {
    currentPage: number;
    lastPage: number;
    perPage: number;
    total: number;
  };
}

// 월 추출 함수
const getMonthKey = (dateStr: string): string => {
  const date = new Date(dateStr);
  return format(date, 'yyyy/MM');
};

// 월 레이블 함수
const getMonthLabel = (monthKey: string): string => {
  const [year, month] = monthKey.split('/');
  return `${year}년 ${parseInt(month)}월`;
};

export function ExpectedExpenseManagement({
  initialData,
  pagination: initialPagination,
}: ExpectedExpenseManagementProps) {
  const router = useRouter();
  const [isPending, startTransition] = useTransition();

  // ===== 상태 관리 =====
  const [searchQuery, setSearchQuery] = useState('');
  const [vendorFilter, setVendorFilter] = useState<string>('all');
  const [sortOption, setSortOption] = useState<SortOption>('latest');
  const [selectedItems, setSelectedItems] = useState<Set<string>>(new Set());
  const [currentPage, setCurrentPage] = useState(initialPagination.currentPage);
  const itemsPerPage = initialPagination.perPage;

  // 예상 지급일 변경 다이얼로그
  const [showDateChangeDialog, setShowDateChangeDialog] = useState(false);
  const [newExpectedDate, setNewExpectedDate] = useState<Date | undefined>(undefined);

  // 삭제 다이얼로그
  const [showDeleteDialog, setShowDeleteDialog] = useState(false);
  const [deleteTargetId, setDeleteTargetId] = useState<string | null>(null);

  // 일괄삭제 다이얼로그
  const [showBulkDeleteDialog, setShowBulkDeleteDialog] = useState(false);

  // 등록/수정 폼 다이얼로그
  const [showFormDialog, setShowFormDialog] = useState(false);
  const [editingItem, setEditingItem] = useState<ExpectedExpenseRecord | null>(null);
  const [formData, setFormData] = useState<Partial<ExpectedExpenseRecord>>({
    expectedPaymentDate: format(new Date(), 'yyyy-MM-dd'),
    settlementDate: '',
    transactionType: 'purchase',
    amount: 0,
    vendorId: '',
    vendorName: '',
    bankAccount: '',
    accountSubject: '',
    paymentStatus: 'pending',
    note: '',
  });
  const [formExpectedDate, setFormExpectedDate] = useState<Date | undefined>(new Date());

  // 거래처/계좌 옵션
  const [clientOptions, setClientOptions] = useState<{ id: string; name: string }[]>([]);
  const [bankAccountOptions, setBankAccountOptions] = useState<{ id: string; bankName: string; accountName: string; accountNumber: string }[]>([]);

  // 날짜 범위 상태 (현재 월 기준)
  const now = new Date();
  const [startDate, setStartDate] = useState(format(new Date(now.getFullYear(), now.getMonth(), 1), 'yyyy-MM-dd'));
  const [endDate, setEndDate] = useState(format(new Date(now.getFullYear(), now.getMonth() + 3, 0), 'yyyy-MM-dd'));

  // API에서 받아온 데이터
  const [data, setData] = useState<ExpectedExpenseRecord[]>(initialData);

  // ===== 거래처/계좌 옵션 로드 =====
  useEffect(() => {
    const loadOptions = async () => {
      const [clientsResult, accountsResult] = await Promise.all([
        getClients(),
        getBankAccounts(),
      ]);
      if (clientsResult.success) setClientOptions(clientsResult.data);
      if (accountsResult.success) setBankAccountOptions(accountsResult.data);
    };
    loadOptions();
  }, []);

  // ===== 폼 초기화 =====
  const resetForm = useCallback(() => {
    setFormData({
      expectedPaymentDate: format(new Date(), 'yyyy-MM-dd'),
      settlementDate: '',
      transactionType: 'purchase',
      amount: 0,
      vendorId: '',
      vendorName: '',
      bankAccount: '',
      accountSubject: '',
      paymentStatus: 'pending',
      note: '',
    });
    setFormExpectedDate(new Date());
    setEditingItem(null);
  }, []);

  // ===== 등록 다이얼로그 열기 =====
  const handleOpenCreateDialog = useCallback(() => {
    resetForm();
    setShowFormDialog(true);
  }, [resetForm]);

  // ===== 수정 다이얼로그 열기 =====
  const handleOpenEditDialog = useCallback((item: ExpectedExpenseRecord) => {
    setEditingItem(item);
    setFormData({
      expectedPaymentDate: item.expectedPaymentDate,
      settlementDate: item.settlementDate,
      transactionType: item.transactionType,
      amount: item.amount,
      vendorId: item.vendorId,
      vendorName: item.vendorName,
      bankAccount: item.bankAccount,
      accountSubject: item.accountSubject,
      paymentStatus: item.paymentStatus,
      note: item.note,
    });
    setFormExpectedDate(item.expectedPaymentDate ? new Date(item.expectedPaymentDate) : new Date());
    setShowFormDialog(true);
  }, []);

  // ===== 폼 제출 (등록/수정) =====
  const handleFormSubmit = useCallback(async () => {
    if (!formData.expectedPaymentDate || !formData.amount) {
      toast.error('예상 지급일과 지출금액은 필수입니다.');
      return;
    }

    startTransition(async () => {
      if (editingItem) {
        // 수정
        const result = await updateExpectedExpense(editingItem.id, formData);
        if (result.success && result.data) {
          setData(prev => prev.map(item => item.id === editingItem.id ? result.data! : item));
          toast.success('미지급비용이 수정되었습니다.');
          setShowFormDialog(false);
          resetForm();
        } else {
          toast.error(result.error || '수정에 실패했습니다.');
        }
      } else {
        // 등록
        const result = await createExpectedExpense(formData);
        if (result.success && result.data) {
          setData(prev => [result.data!, ...prev]);
          toast.success('미지급비용이 등록되었습니다.');
          setShowFormDialog(false);
          resetForm();
        } else {
          toast.error(result.error || '등록에 실패했습니다.');
        }
      }
    });
  }, [formData, editingItem, resetForm]);

  // ===== 일괄 삭제 핸들러 =====
  const handleBulkDelete = useCallback(async () => {
    if (selectedItems.size === 0) return;

    const selectedIds = Array.from(selectedItems);

    startTransition(async () => {
      const result = await deleteExpectedExpenses(selectedIds);
      if (result.success) {
        setData(prev => prev.filter(item => !selectedItems.has(item.id)));
        setSelectedItems(new Set());
        toast.success(`${result.deletedCount || selectedIds.length}건이 삭제되었습니다.`);
      } else {
        toast.error(result.error || '일괄 삭제에 실패했습니다.');
      }
      setShowBulkDeleteDialog(false);
    });
  }, [selectedItems]);

  // ===== 체크박스 핸들러 =====
  const toggleSelection = useCallback((id: string) => {
    setSelectedItems(prev => {
      const newSet = new Set(prev);
      if (newSet.has(id)) newSet.delete(id);
      else newSet.add(id);
      return newSet;
    });
  }, []);

  // ===== 거래처 필터 옵션 (데이터에서 동적 추출) =====
  const vendorFilterOptions = useMemo(() => {
    const vendors = [...new Set(data.map(item => item.vendorName).filter(Boolean))];
    return [
      { value: 'all', label: '전체' },
      ...vendors.map(vendor => ({ value: vendor, label: vendor }))
    ];
  }, [data]);

  // ===== 필터링된 원본 데이터 =====
  const filteredRawData = useMemo(() => {
    let result = data.filter(item =>
      item.vendorName.includes(searchQuery) ||
      item.accountSubject.includes(searchQuery) ||
      item.note.includes(searchQuery)
    );

    // 거래처 필터
    if (vendorFilter !== 'all') {
      result = result.filter(item => item.vendorName === vendorFilter);
    }

    // 정렬 적용
    switch (sortOption) {
      case 'latest':
        result.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
        break;
      case 'oldest':
        result.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
        break;
      default:
        result.sort((a, b) => new Date(a.expectedPaymentDate).getTime() - new Date(b.expectedPaymentDate).getTime());
    }

    return result;
  }, [data, searchQuery, vendorFilter, sortOption]);

  // ===== 월별 그룹핑된 테이블 데이터 (헤더 + 데이터 + 소계 포함) =====
  const tableData = useMemo((): TableRowData[] => {
    const groups: { [monthKey: string]: ExpectedExpenseRecord[] } = {};

    filteredRawData.forEach(item => {
      const monthKey = getMonthKey(item.expectedPaymentDate);
      if (!groups[monthKey]) {
        groups[monthKey] = [];
      }
      groups[monthKey].push(item);
    });

    const sortedMonths = Object.keys(groups).sort();
    const result: TableRowData[] = [];
    let totalExpense = 0;
    let dataIndex = 0; // 데이터 행 순번 추적 (SSR/CSR 일치를 위해 useMemo 내에서 계산)

    sortedMonths.forEach(monthKey => {
      const monthItems = groups[monthKey];
      const monthSubtotal = monthItems.reduce((sum, item) => sum + item.amount, 0);
      totalExpense += monthSubtotal;

      // 월 헤더 추가
      result.push({
        id: `header-${monthKey}`,
        rowType: 'monthHeader',
        monthLabel: getMonthLabel(monthKey),
        expectedPaymentDate: '',
        settlementDate: '',
        transactionType: 'other',
        amount: 0,
        vendorId: '',
        vendorName: '',
        bankAccount: '',
        accountSubject: '',
        paymentStatus: 'pending',
        approvalStatus: 'none',
        note: '',
        createdAt: '',
        updatedAt: '',
      });

      // 데이터 행들 추가 (순번 포함)
      monthItems.forEach(item => {
        dataIndex++;
        result.push({
          ...item,
          rowType: 'data',
          dataIndex, // 미리 계산된 순번
        });
      });

      // 월별 소계 추가
      result.push({
        id: `subtotal-${monthKey}`,
        rowType: 'monthSubtotal',
        monthLabel: getMonthLabel(monthKey),
        subtotalAmount: monthSubtotal,
        expectedPaymentDate: '',
        settlementDate: '',
        transactionType: 'other',
        amount: monthSubtotal,
        vendorId: '',
        vendorName: '',
        bankAccount: '',
        accountSubject: '',
        paymentStatus: 'pending',
        approvalStatus: 'none',
        note: '',
        createdAt: '',
        updatedAt: '',
      });
    });

    // 전체 합계 행들 추가
    const expectedBalance = 10000000;
    const finalBalance = expectedBalance - totalExpense;

    if (filteredRawData.length > 0) {
      result.push({
        id: 'total-expense',
        rowType: 'totalExpense',
        subtotalAmount: totalExpense,
        expectedPaymentDate: '',
        settlementDate: '',
        transactionType: 'other',
        amount: totalExpense,
        vendorId: '',
        vendorName: '',
        bankAccount: '',
        accountSubject: '',
        paymentStatus: 'pending',
        approvalStatus: 'none',
        note: '',
        createdAt: '',
        updatedAt: '',
      });

      result.push({
        id: 'expected-balance',
        rowType: 'expectedBalance',
        subtotalAmount: expectedBalance,
        expectedPaymentDate: '',
        settlementDate: '',
        transactionType: 'other',
        amount: expectedBalance,
        vendorId: '',
        vendorName: '',
        bankAccount: '',
        accountSubject: '',
        paymentStatus: 'pending',
        approvalStatus: 'none',
        note: '',
        createdAt: '',
        updatedAt: '',
      });

      result.push({
        id: 'final-balance',
        rowType: 'finalBalance',
        subtotalAmount: finalBalance,
        expectedPaymentDate: '',
        settlementDate: '',
        transactionType: 'other',
        amount: finalBalance,
        vendorId: '',
        vendorName: '',
        bankAccount: '',
        accountSubject: '',
        paymentStatus: 'pending',
        approvalStatus: 'none',
        note: '',
        createdAt: '',
        updatedAt: '',
      });
    }

    return result;
  }, [filteredRawData]);

  const totalPages = initialPagination.lastPage || Math.ceil(tableData.length / itemsPerPage);

  // ===== 전체 선택 핸들러 (데이터 행만) =====
  const toggleSelectAll = useCallback(() => {
    const dataRows = filteredRawData;
    if (selectedItems.size === dataRows.length && dataRows.length > 0) {
      setSelectedItems(new Set());
    } else {
      setSelectedItems(new Set(dataRows.map(item => item.id)));
    }
  }, [selectedItems.size, filteredRawData]);

  // ===== 액션 핸들러 =====
  // 상세페이지 없음 - 행 클릭 시 이동하지 않음

  const handleDeleteClick = useCallback((id: string) => {
    setDeleteTargetId(id);
    setShowDeleteDialog(true);
  }, []);

  const handleConfirmDelete = useCallback(async () => {
    if (!deleteTargetId) return;

    startTransition(async () => {
      const result = await deleteExpectedExpense(deleteTargetId);
      if (result.success) {
        setData(prev => prev.filter(item => item.id !== deleteTargetId));
        setSelectedItems(prev => {
          const newSet = new Set(prev);
          newSet.delete(deleteTargetId);
          return newSet;
        });
        toast.success('미지급비용이 삭제되었습니다.');
      } else {
        toast.error(result.error || '삭제에 실패했습니다.');
      }
      setShowDeleteDialog(false);
      setDeleteTargetId(null);
    });
  }, [deleteTargetId]);

  // ===== 예상 지급일 변경 핸들러 =====
  const handleOpenDateChangeDialog = useCallback(() => {
    if (selectedItems.size === 0) return;
    setNewExpectedDate(undefined);
    setShowDateChangeDialog(true);
  }, [selectedItems.size]);

  const handleConfirmDateChange = useCallback(async () => {
    if (!newExpectedDate || selectedItems.size === 0) return;

    const newDateStr = format(newExpectedDate, 'yyyy-MM-dd');
    const selectedIds = Array.from(selectedItems);

    startTransition(async () => {
      const result = await updateExpectedPaymentDate(selectedIds, newDateStr);
      if (result.success) {
        setData(prev => prev.map(item =>
          selectedItems.has(item.id)
            ? { ...item, expectedPaymentDate: newDateStr }
            : item
        ));
        toast.success(`${result.updatedCount || selectedIds.length}건의 예상 지급일이 변경되었습니다.`);
        setSelectedItems(new Set());
      } else {
        toast.error(result.error || '예상 지급일 변경에 실패했습니다.');
      }
      setShowDateChangeDialog(false);
      setNewExpectedDate(undefined);
    });
  }, [newExpectedDate, selectedItems]);

  // ===== 선택된 항목 요약 =====
  const selectedItemsSummary = useMemo(() => {
    const selectedData = data.filter(item => selectedItems.has(item.id));
    if (selectedData.length === 0) return { label: '', totalAmount: 0 };

    const firstItem = selectedData[0];
    const remainingCount = selectedData.length - 1;
    const label = remainingCount > 0
      ? `${firstItem.vendorName} 외 ${remainingCount}`
      : firstItem.vendorName;
    const totalAmount = selectedData.reduce((sum, item) => sum + item.amount, 0);

    return { label, totalAmount };
  }, [data, selectedItems]);

  // ===== 테이블 컬럼 =====
  const tableColumns = useMemo(() => [
    { key: 'no', label: '번호', className: 'w-[60px] text-center' },
    { key: 'expectedPaymentDate', label: '예상 지급일' },
    { key: 'accountSubject', label: '항목' },
    { key: 'amount', label: '지출금액', className: 'text-right' },
    { key: 'vendorName', label: '거래처' },
    { key: 'bankAccount', label: '계좌' },
    { key: 'approvalStatus', label: '전자결재', className: 'text-center' },
    { key: 'actions', label: '작업', className: 'w-[100px] text-center' },
  ], []);

  // ===== 전자결재 상태 Badge 스타일 =====
  const getApprovalStatusBadge = (status: ApprovalStatus) => {
    const styles = {
      none: 'border-gray-300 text-gray-600 bg-gray-50',
      pending: 'border-orange-300 text-orange-600 bg-orange-50',
      approved: 'border-green-300 text-green-600 bg-green-50',
      rejected: 'border-red-300 text-red-600 bg-red-50',
    };
    return (
      <Badge variant="outline" className={styles[status]}>
        {APPROVAL_STATUS_LABELS[status]}
      </Badge>
    );
  };

  // ===== 테이블 행 렌더링 =====
  // 컬럼 순서: 체크박스 + 번호 + 예상 지급일 + 항목 + 지출금액 + 거래처 + 계좌 + 전자결재 + 작업
  const renderTableRow = useCallback((
    item: TableRowData,
    index: number,
    globalIndex: number,
    handlers: SelectionHandlers & RowClickHandlers<TableRowData>
  ) => {
    // 월 헤더 행 (9개 컬럼)
    if (item.rowType === 'monthHeader') {
      return (
        <TableRow key={item.id} className="bg-gray-100 hover:bg-gray-100">
          <TableCell colSpan={9} className="py-2 font-semibold text-gray-700">
            {item.monthLabel}
          </TableCell>
        </TableRow>
      );
    }

    // 월별 소계 행
    if (item.rowType === 'monthSubtotal') {
      return (
        <TableRow key={item.id} className="bg-blue-50 hover:bg-blue-50">
          <TableCell className="text-center"></TableCell>
          <TableCell colSpan={3} className="text-right font-semibold text-blue-700">
            {item.monthLabel} 소계
          </TableCell>
          <TableCell className="text-right font-bold text-blue-700">
            {item.subtotalAmount?.toLocaleString()}
          </TableCell>
          <TableCell colSpan={4}></TableCell>
        </TableRow>
      );
    }

    // 지출 합계 행
    if (item.rowType === 'totalExpense') {
      return (
        <TableRow key={item.id} className="bg-gray-100 hover:bg-gray-100">
          <TableCell className="text-center"></TableCell>
          <TableCell colSpan={3} className="text-right font-bold">
            지출 합계
          </TableCell>
          <TableCell className="text-right font-bold text-red-600">
            {item.subtotalAmount?.toLocaleString()}
          </TableCell>
          <TableCell colSpan={4}></TableCell>
        </TableRow>
      );
    }

    // 예상 잔액 행
    if (item.rowType === 'expectedBalance') {
      return (
        <TableRow key={item.id} className="bg-gray-100 hover:bg-gray-100">
          <TableCell className="text-center"></TableCell>
          <TableCell colSpan={3} className="text-right font-bold">
            예상 잔액
          </TableCell>
          <TableCell className="text-right font-bold">
            {item.subtotalAmount?.toLocaleString()}
          </TableCell>
          <TableCell colSpan={4}></TableCell>
        </TableRow>
      );
    }

    // 최종 잔액 행
    if (item.rowType === 'finalBalance') {
      return (
        <TableRow key={item.id} className="bg-orange-50 hover:bg-orange-50">
          <TableCell className="text-center"></TableCell>
          <TableCell colSpan={3} className="text-right font-bold">
            최종 잔액
          </TableCell>
          <TableCell className="text-right font-bold text-orange-600">
            {item.subtotalAmount?.toLocaleString()}원
          </TableCell>
          <TableCell colSpan={4}></TableCell>
        </TableRow>
      );
    }

    // 일반 데이터 행
    const isSelected = selectedItems.has(item.id);

    return (
      <TableRow
        key={item.id}
        className="hover:bg-muted/50"
      >
        <TableCell className="text-center">
          <Checkbox checked={isSelected} onCheckedChange={() => toggleSelection(item.id)} />
        </TableCell>
        <TableCell className="text-center">
          <span className="inline-flex items-center justify-center w-6 h-6 rounded-full bg-red-500 text-white text-xs font-medium">
            {item.dataIndex}
          </span>
        </TableCell>
        <TableCell>{item.expectedPaymentDate}</TableCell>
        <TableCell>{item.accountSubject}</TableCell>
        <TableCell className="text-right font-medium text-red-600">
          {item.amount.toLocaleString()}
        </TableCell>
        <TableCell>{item.vendorName}</TableCell>
        <TableCell>{item.bankAccount}</TableCell>
        <TableCell className="text-center">
          {getApprovalStatusBadge(item.approvalStatus)}
        </TableCell>
        <TableCell className="text-center">
          <div className="flex items-center justify-center gap-1">
            <Button
              variant="ghost"
              size="icon"
              className="h-7 w-7"
              onClick={(e) => {
                e.stopPropagation();
                handleOpenEditDialog(item);
              }}
            >
              <Pencil className="h-4 w-4 text-gray-500" />
            </Button>
            <Button
              variant="ghost"
              size="icon"
              className="h-7 w-7"
              onClick={(e) => {
                e.stopPropagation();
                handleDeleteClick(item.id);
              }}
            >
              <Trash2 className="h-4 w-4 text-red-500" />
            </Button>
          </div>
        </TableCell>
      </TableRow>
    );
  }, [selectedItems, toggleSelection, handleOpenEditDialog, handleDeleteClick]);

  // ===== 모바일 카드 렌더링 =====
  const renderMobileCard = useCallback((
    item: TableRowData,
    index: number,
    globalIndex: number,
    handlers: SelectionHandlers & RowClickHandlers<TableRowData>
  ) => {
    const isSelected = selectedItems.has(item.id);
    const onToggle = () => toggleSelection(item.id);
    // 헤더/소계/합계 행은 모바일에서 다르게 표시
    if (item.rowType !== 'data') {
      if (item.rowType === 'monthHeader') {
        return (
          <div className="bg-gray-100 p-3 rounded-lg font-semibold text-gray-700">
            {item.monthLabel}
          </div>
        );
      }
      if (item.rowType === 'monthSubtotal') {
        return (
          <div className="bg-blue-50 p-3 rounded-lg flex justify-between">
            <span className="font-semibold text-blue-700">{item.monthLabel} 소계</span>
            <span className="font-bold text-blue-700">{item.subtotalAmount?.toLocaleString()}원</span>
          </div>
        );
      }
      if (item.rowType === 'totalExpense') {
        return (
          <div className="bg-gray-100 p-3 rounded-lg flex justify-between">
            <span className="font-bold">지출 합계</span>
            <span className="font-bold text-red-600">{item.subtotalAmount?.toLocaleString()}원</span>
          </div>
        );
      }
      if (item.rowType === 'expectedBalance') {
        return (
          <div className="bg-gray-100 p-3 rounded-lg flex justify-between">
            <span className="font-bold">예상 잔액</span>
            <span className="font-bold">{item.subtotalAmount?.toLocaleString()}원</span>
          </div>
        );
      }
      if (item.rowType === 'finalBalance') {
        return (
          <div className="bg-orange-50 p-3 rounded-lg flex justify-between">
            <span className="font-bold">최종 잔액</span>
            <span className="font-bold text-orange-600">{item.subtotalAmount?.toLocaleString()}원</span>
          </div>
        );
      }
      return null;
    }

    return (
      <ListMobileCard
        id={item.id}
        title={item.vendorName}
        headerBadges={
          <>
            <Badge variant="outline">{TRANSACTION_TYPE_LABELS[item.transactionType]}</Badge>
            <Badge variant="outline" className={
              item.paymentStatus === 'paid' ? 'border-green-300 text-green-600 bg-green-50' :
              item.paymentStatus === 'partial' ? 'border-blue-300 text-blue-600 bg-blue-50' :
              item.paymentStatus === 'pending' ? 'border-orange-300 text-orange-600 bg-orange-50' :
              'border-red-300 text-red-600 bg-red-50'
            }>
              {PAYMENT_STATUS_LABELS[item.paymentStatus]}
            </Badge>
            {getApprovalStatusBadge(item.approvalStatus)}
          </>
        }
        isSelected={isSelected}
        onToggleSelection={onToggle}
        infoGrid={
          <div className="grid grid-cols-2 gap-3">
            <InfoField label="예상 지급일" value={item.expectedPaymentDate} />
            <InfoField label="지출금액" value={`${item.amount.toLocaleString()}원`} />
            <InfoField label="거래처" value={item.vendorName} />
            <InfoField label="계좌" value={item.bankAccount} />
          </div>
        }
      />
    );
  }, []);

  // ===== 선택된 항목 데이터 가져오기 =====
  const getSelectedItemsData = useCallback(() => {
    return data.filter(item => selectedItems.has(item.id));
  }, [data, selectedItems]);

  // ===== 전자결재 페이지로 이동 (선택 데이터 전달) =====
  const handleElectronicApproval = useCallback(() => {
    const selectedData = getSelectedItemsData();
    // 선택된 항목 ID들을 쿼리 파라미터로 전달
    const selectedIds = selectedData.map(item => item.id).join(',');
    router.push(`/ko/approval/draft/new?type=expected-expense&items=${encodeURIComponent(selectedIds)}`);
  }, [getSelectedItemsData, router]);

  // ===== UniversalListPage Config =====
  const config: UniversalListConfig<TableRowData> = useMemo(
    () => ({
      // 페이지 기본 정보
      title: '지출 예상 내역서',
      description: '지출 예상 내역을 등록하고 조회합니다',
      icon: Receipt,
      basePath: '/accounting/expected-expense',

      // ID 추출
      idField: 'id',

      // API 액션
      actions: {
        getList: async () => {
          return {
            success: true,
            data: tableData,
            totalCount: initialPagination.total || filteredRawData.length,
          };
        },
      },

      // 테이블 컬럼
      columns: tableColumns,

      // 클라이언트 사이드 필터링 (이미 tableData에서 필터링 완료)
      clientSideFiltering: false,
      itemsPerPage,

      // 검색
      searchPlaceholder: '거래처, 계정과목, 적요 검색...',
      onSearchChange: setSearchQuery,

      // 행 번호 숨기기 (커스텀 번호 사용)
      showRowNumber: false,

      // 날짜 범위 선택기
      dateRangeSelector: {
        enabled: true,
        startDate,
        endDate,
        onStartDateChange: setStartDate,
        onEndDateChange: setEndDate,
      },

      // 모바일 필터 설정
      filterConfig: [
        {
          key: 'transactionType',
          label: '거래유형',
          type: 'single',
          options: TRANSACTION_TYPE_FILTER_OPTIONS.filter(o => o.value !== 'all'),
        },
        {
          key: 'paymentStatus',
          label: '지급상태',
          type: 'single',
          options: PAYMENT_STATUS_FILTER_OPTIONS.filter(o => o.value !== 'all'),
        },
        {
          key: 'sortBy',
          label: '정렬',
          type: 'single',
          options: SORT_OPTIONS,
        },
      ],
      initialFilters: {
        transactionType: 'all',
        paymentStatus: 'all',
        sortBy: sortOption,
      },
      filterTitle: '예상비용 필터',

      // 테이블 헤더 액션 (거래처/정렬 필터)
      tableHeaderActions: () => (
        <div className="flex items-center gap-2">
          {/* 거래처 필터 */}
          <Select value={vendorFilter} onValueChange={setVendorFilter}>
            <SelectTrigger className="w-[140px] h-8 text-sm">
              <SelectValue placeholder="전체" />
            </SelectTrigger>
            <SelectContent>
              {vendorFilterOptions.map((option) => (
                <SelectItem key={option.value} value={option.value}>
                  {option.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>

          {/* 정렬 필터 (최신순/등록순) */}
          <Select value={sortOption} onValueChange={(value) => setSortOption(value as SortOption)}>
            <SelectTrigger className="w-[100px] h-8 text-sm">
              <SelectValue placeholder="최신순" />
            </SelectTrigger>
            <SelectContent>
              {SORT_OPTIONS.map((option) => (
                <SelectItem key={option.value} value={option.value}>
                  {option.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
      ),

      // 테이블 앞 컨텐츠 (액션 버튼)
      beforeTableContent: (
        <div className="flex items-center gap-2 flex-wrap">
          {/* 등록 버튼 */}
          <Button
            size="sm"
            onClick={handleOpenCreateDialog}
          >
            <Plus className="h-4 w-4 mr-1" />
            등록
          </Button>

          {/* 예상 지급일 변경 버튼 - 1개 이상 선택 시 활성화 */}
          <Button
            variant="outline"
            size="sm"
            onClick={handleOpenDateChangeDialog}
            disabled={selectedItems.size === 0}
          >
            <CalendarIcon className="h-4 w-4 mr-1" />
            예상 지급일 변경 {selectedItems.size > 0 && `(${selectedItems.size})`}
          </Button>

          {/* 전자결재 버튼 - 1개 이상 선택 시 활성화 */}
          <Button
            variant="outline"
            size="sm"
            onClick={handleElectronicApproval}
            disabled={selectedItems.size === 0}
          >
            <FileText className="h-4 w-4 mr-1" />
            전자결재 {selectedItems.size > 0 && `(${selectedItems.size})`}
          </Button>

          {/* 일괄삭제 버튼 - 1개 이상 선택 시 활성화 */}
          <Button
            variant="outline"
            size="sm"
            onClick={() => setShowBulkDeleteDialog(true)}
            disabled={selectedItems.size === 0}
            className="text-red-600 hover:text-red-700 hover:bg-red-50"
          >
            <Trash2 className="h-4 w-4 mr-1" />
            일괄삭제 {selectedItems.size > 0 && `(${selectedItems.size})`}
          </Button>
        </div>
      ),

      // Stats 카드
      computeStats: (): StatCard[] => {
        const totalExpense = filteredRawData.reduce((sum, d) => sum + d.amount, 0);
        const expectedBalance = 10000000;

        return [
          { label: '지출 합계', value: `${totalExpense.toLocaleString()}원`, icon: Receipt, iconColor: 'text-red-500' },
          { label: '예상 잔액', value: `${expectedBalance.toLocaleString()}원`, icon: Receipt, iconColor: 'text-blue-500' },
        ];
      },

      // 테이블 행 렌더링
      renderTableRow,

      // 모바일 카드 렌더링
      renderMobileCard,
    }),
    [
      tableData,
      tableColumns,
      filteredRawData,
      initialPagination,
      itemsPerPage,
      startDate,
      endDate,
      vendorFilter,
      vendorFilterOptions,
      sortOption,
      selectedItems,
      handleOpenCreateDialog,
      handleOpenDateChangeDialog,
      handleElectronicApproval,
      renderTableRow,
      renderMobileCard,
    ]
  );

  return (
    <>
      <UniversalListPage
        config={config}
        initialData={tableData}
        externalPagination={{
          currentPage,
          totalPages: totalPages || 1,
          totalItems: initialPagination.total || filteredRawData.length,
          itemsPerPage,
          onPageChange: setCurrentPage,
        }}
        externalSelection={{
          selectedItems,
          onToggleSelection: toggleSelection,
          onToggleSelectAll: toggleSelectAll,
          getItemId: (item: TableRowData) => item.id,
        }}
      />

      {/* 삭제 확인 다이얼로그 */}
      <AlertDialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>지출 예상 내역 삭제</AlertDialogTitle>
            <AlertDialogDescription>
              이 지출 예상 내역을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>취소</AlertDialogCancel>
            <AlertDialogAction
              onClick={handleConfirmDelete}
              className="bg-red-600 hover:bg-red-700"
            >
              삭제
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>

      {/* 예상 지급일 변경 다이얼로그 */}
      <Dialog open={showDateChangeDialog} onOpenChange={setShowDateChangeDialog}>
        <DialogContent className="sm:max-w-[500px]">
          <DialogHeader>
            <DialogTitle>예상 지급일 변경</DialogTitle>
          </DialogHeader>
          <div className="space-y-4 py-4">
            {/* 선택된 항목 리스트 */}
            <div className="space-y-2">
              <label className="text-sm font-medium text-gray-700">선택된 항목 ({selectedItems.size}건)</label>
              <div className="max-h-[200px] overflow-y-auto border rounded-lg">
                {data.filter(item => selectedItems.has(item.id)).map((item, idx) => (
                  <div
                    key={item.id}
                    className={`flex items-center justify-between px-4 py-2 ${idx !== 0 ? 'border-t' : ''}`}
                  >
                    <div className="flex flex-col">
                      <span className="text-sm font-medium">{item.vendorName}</span>
                      <span className="text-xs text-gray-500">{item.accountSubject} • {item.expectedPaymentDate}</span>
                    </div>
                    <span className="font-semibold text-red-600">{item.amount.toLocaleString()}원</span>
                  </div>
                ))}
              </div>
            </div>

            {/* 합계 */}
            <div className="flex items-center justify-between p-3 bg-gray-100 rounded-lg">
              <span className="text-sm font-medium text-gray-700">합계</span>
              <span className="font-bold text-lg">{selectedItemsSummary.totalAmount.toLocaleString()}원</span>
            </div>

            {/* 예상 지급일 선택 */}
            <div className="space-y-2">
              <label className="text-sm font-medium text-gray-700">변경할 예상 지급일</label>
              <Popover>
                <PopoverTrigger asChild>
                  <Button
                    variant="outline"
                    className="w-full justify-start text-left font-normal"
                  >
                    <CalendarIcon className="mr-2 h-4 w-4" />
                    {newExpectedDate ? format(newExpectedDate, 'yyyy-MM-dd') : '날짜 선택'}
                  </Button>
                </PopoverTrigger>
                <PopoverContent className="w-auto p-0" align="start">
                  <Calendar
                    mode="single"
                    selected={newExpectedDate}
                    onSelect={setNewExpectedDate}
                  />
                </PopoverContent>
              </Popover>
            </div>
          </div>

          {/* 버튼 영역 */}
          <div className="flex gap-3 justify-end">
            <Button
              variant="outline"
              onClick={() => setShowDateChangeDialog(false)}
            >
              취소
            </Button>
            <Button
              onClick={handleConfirmDateChange}
              disabled={!newExpectedDate}
            >
              저장
            </Button>
          </div>
        </DialogContent>
      </Dialog>

      {/* 등록/수정 폼 다이얼로그 */}
      <Dialog open={showFormDialog} onOpenChange={setShowFormDialog}>
        <DialogContent className="sm:max-w-[600px]">
          <DialogHeader>
            <DialogTitle>{editingItem ? '미지급비용 수정' : '미지급비용 등록'}</DialogTitle>
          </DialogHeader>
          <div className="space-y-4 py-4">
            {/* 예상 지급일 */}
            <div className="grid grid-cols-2 gap-4">
              <div className="space-y-2">
                <Label>예상 지급일 *</Label>
                <Popover>
                  <PopoverTrigger asChild>
                    <Button
                      variant="outline"
                      className="w-full justify-start text-left font-normal"
                    >
                      <CalendarIcon className="mr-2 h-4 w-4" />
                      {formExpectedDate ? format(formExpectedDate, 'yyyy-MM-dd') : '날짜 선택'}
                    </Button>
                  </PopoverTrigger>
                  <PopoverContent className="w-auto p-0" align="start">
                    <Calendar
                      mode="single"
                      selected={formExpectedDate}
                      onSelect={(date) => {
                        setFormExpectedDate(date);
                        if (date) {
                          setFormData(prev => ({ ...prev, expectedPaymentDate: format(date, 'yyyy-MM-dd') }));
                        }
                      }}
                    />
                  </PopoverContent>
                </Popover>
              </div>

              {/* 거래유형 */}
              <div className="space-y-2">
                <Label>거래유형</Label>
                <Select
                  value={formData.transactionType}
                  onValueChange={(value) => setFormData(prev => ({ ...prev, transactionType: value as TransactionType }))}
                >
                  <SelectTrigger>
                    <SelectValue placeholder="거래유형 선택" />
                  </SelectTrigger>
                  <SelectContent>
                    {TRANSACTION_TYPE_FILTER_OPTIONS.filter(opt => opt.value !== 'all').map((option) => (
                      <SelectItem key={option.value} value={option.value}>
                        {option.label}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>
            </div>

            {/* 거래처 / 금액 */}
            <div className="grid grid-cols-2 gap-4">
              <div className="space-y-2">
                <Label>거래처</Label>
                <Select
                  value={formData.vendorId}
                  onValueChange={(value) => {
                    const selected = clientOptions.find(c => c.id === value);
                    setFormData(prev => ({
                      ...prev,
                      vendorId: value,
                      vendorName: selected?.name || '',
                    }));
                  }}
                >
                  <SelectTrigger>
                    <SelectValue placeholder="거래처 선택" />
                  </SelectTrigger>
                  <SelectContent>
                    {clientOptions.map((option) => (
                      <SelectItem key={option.id} value={option.id}>
                        {option.name}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>

              <div className="space-y-2">
                <Label>지출금액 *</Label>
                <CurrencyInput
                  value={formData.amount}
                  onChange={(value) => setFormData(prev => ({ ...prev, amount: value ?? 0 }))}
                  placeholder="금액 입력"
                />
              </div>
            </div>

            {/* 계좌 / 계정과목 */}
            <div className="grid grid-cols-2 gap-4">
              <div className="space-y-2">
                <Label>출금계좌</Label>
                <Select
                  value={formData.bankAccount}
                  onValueChange={(value) => setFormData(prev => ({ ...prev, bankAccount: value }))}
                >
                  <SelectTrigger>
                    <SelectValue placeholder="계좌 선택" />
                  </SelectTrigger>
                  <SelectContent>
                    {bankAccountOptions.map((option) => (
                      <SelectItem key={option.id} value={`${option.bankName} ${option.accountNumber}`}>
                        {option.bankName} {option.accountNumber} ({option.accountName})
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>

              <div className="space-y-2">
                <Label>계정과목</Label>
                <Select
                  value={formData.accountSubject}
                  onValueChange={(value) => setFormData(prev => ({ ...prev, accountSubject: value }))}
                >
                  <SelectTrigger>
                    <SelectValue placeholder="계정과목 선택" />
                  </SelectTrigger>
                  <SelectContent>
                    {ACCOUNT_SUBJECT_OPTIONS.filter(opt => opt.value !== 'all').map((option) => (
                      <SelectItem key={option.value} value={option.value}>
                        {option.label}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>
            </div>

            {/* 결제상태 */}
            <div className="space-y-2">
              <Label>결제상태</Label>
              <Select
                value={formData.paymentStatus}
                onValueChange={(value) => setFormData(prev => ({ ...prev, paymentStatus: value as PaymentStatus }))}
              >
                <SelectTrigger className="w-[200px]">
                  <SelectValue placeholder="결제상태 선택" />
                </SelectTrigger>
                <SelectContent>
                  {PAYMENT_STATUS_FILTER_OPTIONS.filter(opt => opt.value !== 'all').map((option) => (
                    <SelectItem key={option.value} value={option.value}>
                      {option.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>

            {/* 비고 */}
            <div className="space-y-2">
              <Label>비고</Label>
              <Textarea
                value={formData.note || ''}
                onChange={(e) => setFormData(prev => ({ ...prev, note: e.target.value }))}
                placeholder="비고 입력"
                rows={3}
              />
            </div>
          </div>

          {/* 버튼 영역 */}
          <div className="flex gap-3 justify-end">
            <Button
              variant="outline"
              onClick={() => {
                setShowFormDialog(false);
                resetForm();
              }}
            >
              취소
            </Button>
            <Button
              onClick={handleFormSubmit}
              disabled={isPending}
            >
              {isPending ? '처리중...' : (editingItem ? '수정' : '등록')}
            </Button>
          </div>
        </DialogContent>
      </Dialog>

      {/* 일괄삭제 확인 다이얼로그 */}
      <AlertDialog open={showBulkDeleteDialog} onOpenChange={setShowBulkDeleteDialog}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>일괄 삭제</AlertDialogTitle>
            <AlertDialogDescription>
              선택한 {selectedItems.size}건의 미지급비용을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다.
            </AlertDialogDescription>
          </AlertDialogHeader>
          <div className="max-h-[200px] overflow-y-auto border rounded-lg my-4">
            {data.filter(item => selectedItems.has(item.id)).map((item, idx) => (
              <div
                key={item.id}
                className={`flex items-center justify-between px-4 py-2 ${idx !== 0 ? 'border-t' : ''}`}
              >
                <div className="flex flex-col">
                  <span className="text-sm font-medium">{item.vendorName}</span>
                  <span className="text-xs text-gray-500">{item.accountSubject} • {item.expectedPaymentDate}</span>
                </div>
                <span className="font-semibold text-red-600">{item.amount.toLocaleString()}원</span>
              </div>
            ))}
          </div>
          <div className="flex items-center justify-between p-3 bg-gray-100 rounded-lg">
            <span className="text-sm font-medium text-gray-700">합계</span>
            <span className="font-bold text-lg text-red-600">{selectedItemsSummary.totalAmount.toLocaleString()}원</span>
          </div>
          <AlertDialogFooter className="mt-4">
            <AlertDialogCancel>취소</AlertDialogCancel>
            <AlertDialogAction
              onClick={handleBulkDelete}
              className="bg-red-600 hover:bg-red-700"
              disabled={isPending}
            >
              {isPending ? '삭제중...' : '삭제'}
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </>
  );
}
