'use client';

import { useState, useMemo, useCallback, useEffect, useRef, useTransition } from 'react';
import { Download, FileText, Save, Loader2, RefreshCw, ChevronDown, ChevronUp } from 'lucide-react';
import { formatNumber } from '@/lib/utils/amount';
import { Button } from '@/components/ui/button';
import { Switch } from '@/components/ui/switch';
import { Textarea } from '@/components/ui/textarea';
import { Card, CardContent } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, TableFooter } from '@/components/ui/table';
import { MobileCard } from '@/components/organisms/MobileCard';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { PageLayout } from '@/components/organisms/PageLayout';
import { PageHeader } from '@/components/organisms/PageHeader';
import { SearchFilter } from '@/components/organisms/SearchFilter';
import type {
  VendorReceivables,
  CategoryType,
  SortOption,
  ReceivablesListResponse,
  MemoUpdateRequest,
} from './types';
import {
  CATEGORY_LABELS,
  SORT_OPTIONS,
} from './types';
import { getReceivablesList, getReceivablesSummary, updateOverdueStatus, updateMemos } from './actions';
import { toast } from 'sonner';
import { filterByText } from '@/lib/utils/search';
import { downloadExcel, type ExcelColumn } from '@/lib/utils/excel-download';
import { isNextRedirectError } from '@/lib/utils/redirect-error';
import { usePermission } from '@/hooks/usePermission';

// ===== Props 인터페이스 =====
interface ReceivablesStatusProps {
  highlightVendorId?: string;
  initialData?: ReceivablesListResponse;
  initialSummary?: {
    totalCarryForward: number;
    totalSales: number;
    totalDeposits: number;
    totalBills: number;
    totalReceivables: number;
    vendorCount: number;
    overdueVendorCount: number;
  };
}

// ===== 연도 옵션 생성 (0 = 최근 1년) =====
const YEAR_RECENT = 0; // 최근 1년 옵션 값
const generateYearOptions = (): Array<{ value: number; label: string }> => {
  const currentYear = new Date().getFullYear();
  const years = Array.from({ length: 5 }, (_, i) => ({
    value: currentYear - i,
    label: `${currentYear - i}년`,
  }));
  return [{ value: YEAR_RECENT, label: '최근 1년' }, ...years];
};

// ===== 카테고리 순서 (메모 제외) =====
const _categoryOrder: CategoryType[] = ['sales', 'deposit', 'bill', 'receivable'];

export function ReceivablesStatus({ highlightVendorId, initialData, initialSummary }: ReceivablesStatusProps) {
  const { canExport } = usePermission();
  // ===== Refs =====
  const highlightRowRef = useRef<HTMLTableRowElement>(null);

  // ===== 상태 관리 =====
  const [isPending, startTransition] = useTransition();
  const [selectedYear, setSelectedYear] = useState<number>(YEAR_RECENT); // 기본: 최근 1년
  const [sortOption, setSortOption] = useState<SortOption>('overdueFirst'); // 기본: 연체 업체 우선
  const [searchQuery, setSearchQuery] = useState('');
  const [monthLabels, setMonthLabels] = useState<string[]>(initialData?.monthLabels || []);
  const [data, setData] = useState<VendorReceivables[]>(initialData?.items || []);
  const [originalOverdueMap, setOriginalOverdueMap] = useState<Map<string, boolean>>(new Map());
  const [originalMemoMap, setOriginalMemoMap] = useState<Map<string, string>>(new Map());
  const [, setSummary] = useState(initialSummary || {
    totalCarryForward: 0,
    totalSales: 0,
    totalDeposits: 0,
    totalBills: 0,
    totalReceivables: 0,
    vendorCount: 0,
    overdueVendorCount: 0,
  });
  const [isLoading, setIsLoading] = useState(!initialData?.items?.length);
  const [expandedMemos, setExpandedMemos] = useState<Set<string>>(new Set());

  // ===== 데이터 로드 =====
  const loadData = useCallback(async () => {
    setIsLoading(true);
    try {
      const [listResult, summaryResult] = await Promise.all([
        getReceivablesList({ year: selectedYear, search: searchQuery || undefined }),
        getReceivablesSummary({ year: selectedYear }),
      ]);

      if (listResult.success) {
        setMonthLabels(listResult.data.monthLabels);
        setData(listResult.data.items);
        // 원본 연체 상태 저장
        const overdueMap = new Map<string, boolean>();
        const memoMap = new Map<string, string>();
        listResult.data.items.forEach(vendor => {
          overdueMap.set(vendor.id, vendor.isOverdue);
          memoMap.set(vendor.id, vendor.memo || '');
        });
        setOriginalOverdueMap(overdueMap);
        setOriginalMemoMap(memoMap);
      }

      if (summaryResult.success && summaryResult.data) {
        setSummary(summaryResult.data);
      }
    } catch (error) {
      if (isNextRedirectError(error)) throw error;
      console.error('Failed to load receivables:', error);
    } finally {
      setIsLoading(false);
    }
  }, [selectedYear, searchQuery]);

  // ===== 초기 로드 및 필터 변경시 재로드 =====
  useEffect(() => {
    loadData();
  }, [loadData]);

  // ===== 하이라이트된 행으로 스크롤 =====
  useEffect(() => {
    if (highlightVendorId && highlightRowRef.current) {
      highlightRowRef.current.scrollIntoView({ behavior: 'smooth', block: 'center' });
    }
  }, [highlightVendorId]);

  // ===== 필터링된 데이터 =====
  const filteredData = useMemo(() => {
    return filterByText(data, searchQuery, ['vendorName']);
  }, [data, searchQuery]);

  // ===== 정렬된 데이터 =====
  // 정렬에는 원본 연체 상태(originalOverdueMap)를 사용하여 토글 시 위치 이동 방지
  const sortedData = useMemo(() => {
    const sorted = [...filteredData];

    switch (sortOption) {
      case 'overdueFirst':
        // 연체 업체 우선 (원본 연체 상태 기준으로 정렬, 토글해도 위치 유지)
        sorted.sort((a, b) => {
          const aOriginalOverdue = originalOverdueMap.get(a.id) ?? a.isOverdue;
          const bOriginalOverdue = originalOverdueMap.get(b.id) ?? b.isOverdue;
          if (aOriginalOverdue !== bOriginalOverdue) {
            return aOriginalOverdue ? -1 : 1;
          }
          return a.vendorName.localeCompare(b.vendorName, 'ko');
        });
        break;
      case 'vendorName':
        // 거래처명 순
        sorted.sort((a, b) => a.vendorName.localeCompare(b.vendorName, 'ko'));
        break;
      case 'totalDesc':
        // 금액 높은순 (미수금 합계 기준)
        sorted.sort((a, b) => {
          const aTotal = a.categories.find(c => c.category === 'receivable')?.amounts.total || 0;
          const bTotal = b.categories.find(c => c.category === 'receivable')?.amounts.total || 0;
          return bTotal - aTotal;
        });
        break;
      case 'totalAsc':
        // 금액 낮은순 (미수금 합계 기준)
        sorted.sort((a, b) => {
          const aTotal = a.categories.find(c => c.category === 'receivable')?.amounts.total || 0;
          const bTotal = b.categories.find(c => c.category === 'receivable')?.amounts.total || 0;
          return aTotal - bTotal;
        });
        break;
    }

    return sorted;
  }, [filteredData, sortOption, originalOverdueMap]);

  // ===== 연체 토글 핸들러 =====
  const handleOverdueToggle = useCallback((vendorId: string, checked: boolean) => {
    setData(prev => prev.map(vendor =>
      vendor.id === vendorId ? { ...vendor, isOverdue: checked } : vendor
    ));
  }, []);

  // ===== 메모 변경 핸들러 =====
  const handleMemoChange = useCallback((vendorId: string, memo: string) => {
    setData(prev => prev.map(vendor =>
      vendor.id === vendorId ? { ...vendor, memo } : vendor
    ));
  }, []);

  // ===== 메모 펼치기/접기 토글 =====
  const toggleMemoExpand = useCallback((vendorId: string) => {
    setExpandedMemos(prev => {
      const newSet = new Set(prev);
      if (newSet.has(vendorId)) {
        newSet.delete(vendorId);
      } else {
        newSet.add(vendorId);
      }
      return newSet;
    });
  }, []);

  // ===== 엑셀 다운로드 핸들러 (프론트 xlsx 생성) =====
  const handleExcelDownload = useCallback(async () => {
    try {
      toast.info('엑셀 파일 생성 중...');
      // 데이터가 이미 로드되어 있으므로 sortedData 사용
      if (sortedData.length === 0) {
        toast.warning('다운로드할 데이터가 없습니다.');
        return;
      }
      // 동적 월 컬럼 포함 엑셀 컬럼 생성
      const columns: ExcelColumn<Record<string, unknown>>[] = [
        { header: '거래처', key: 'vendorName', width: 20 },
        { header: '연체', key: 'isOverdue', width: 8 },
        ...monthLabels.map((label, idx) => ({
          header: label, key: `month_${idx}`, width: 12,
        })),
        { header: '합계', key: 'total', width: 14 },
        { header: '메모', key: 'memo', width: 20 },
      ];
      // 미수금 카테고리 기준으로 플랫 데이터 생성
      const exportData = sortedData.map(vendor => {
        const receivable = vendor.categories.find(c => c.category === 'receivable');
        const row: Record<string, unknown> = {
          vendorName: vendor.vendorName,
          isOverdue: vendor.isOverdue ? '연체' : '',
        };
        monthLabels.forEach((_, idx) => {
          row[`month_${idx}`] = receivable?.amounts.values[idx] || 0;
        });
        row.total = receivable?.amounts.total || 0;
        row.memo = vendor.memo || '';
        return row;
      });
      await downloadExcel({ data: exportData, columns, filename: '미수금현황', sheetName: '미수금현황' });
      toast.success('엑셀 다운로드 완료');
    } catch {
      toast.error('엑셀 다운로드에 실패했습니다.');
    }
  }, [sortedData, monthLabels]);

  // ===== 변경된 연체 항목 확인 =====
  const changedOverdueItems = useMemo(() => {
    return data.filter(vendor => {
      const originalValue = originalOverdueMap.get(vendor.id);
      return originalValue !== undefined && originalValue !== vendor.isOverdue;
    }).map(vendor => ({
      id: vendor.id,
      isOverdue: vendor.isOverdue,
    }));
  }, [data, originalOverdueMap]);

  // ===== 변경된 메모 항목 확인 =====
  const changedMemoItems = useMemo(() => {
    return data.filter(vendor => {
      const originalMemo = originalMemoMap.get(vendor.id);
      return originalMemo !== undefined && originalMemo !== vendor.memo;
    }).map(vendor => ({
      id: vendor.id,
      memo: vendor.memo,
    }));
  }, [data, originalMemoMap]);

  // ===== 총 변경 항목 수 =====
  const totalChangedCount = changedOverdueItems.length + changedMemoItems.length;

  // ===== 저장 핸들러 =====
  const handleSave = useCallback(async () => {
    if (totalChangedCount === 0) {
      toast.info('변경된 항목이 없습니다.');
      return;
    }

    startTransition(async () => {
      const promises: Promise<{ success: boolean; error?: string }>[] = [];

      // 연체 상태 업데이트
      if (changedOverdueItems.length > 0) {
        promises.push(updateOverdueStatus(changedOverdueItems));
      }

      // 메모 업데이트
      if (changedMemoItems.length > 0) {
        promises.push(updateMemos(changedMemoItems as MemoUpdateRequest[]));
      }

      const results = await Promise.all(promises);
      const allSuccess = results.every(r => r.success);

      if (allSuccess) {
        // 원본 상태 업데이트
        const newOverdueMap = new Map(originalOverdueMap);
        changedOverdueItems.forEach(item => {
          newOverdueMap.set(item.id, item.isOverdue);
        });
        setOriginalOverdueMap(newOverdueMap);

        const newMemoMap = new Map(originalMemoMap);
        changedMemoItems.forEach(item => {
          newMemoMap.set(item.id, item.memo);
        });
        setOriginalMemoMap(newMemoMap);

        toast.success(`${totalChangedCount}건이 저장되었습니다.`);
      } else {
        const errors = results.filter(r => !r.success).map(r => r.error).join(', ');
        toast.error(errors || '저장에 실패했습니다.');
      }
    });
  }, [changedOverdueItems, changedMemoItems, totalChangedCount, originalOverdueMap, originalMemoMap]);

  // ===== 금액 포맷 =====
  const formatAmount = (amount: number) => {
    if (amount === 0) return '';
    return formatNumber(amount);
  };

  // ===== 합계 계산 (동적 월) =====
  const grandTotals = useMemo(() => {
    const monthCount = monthLabels.length || 12;
    const values = new Array(monthCount).fill(0);
    let total = 0;

    filteredData.forEach(vendor => {
      const receivableCat = vendor.categories.find(c => c.category === 'receivable');
      if (receivableCat) {
        receivableCat.amounts.values.forEach((val, idx) => {
          if (idx < monthCount) {
            values[idx] += val;
          }
        });
        total += receivableCat.amounts.total;
      }
    });

    return { values, total };
  }, [filteredData, monthLabels.length]);

  // ===== 월 개수 (동적) =====
  const monthCount = monthLabels.length || 12;

  // ===== 카테고리 순서 (메모 제외 - 별도 렌더링) =====
  const categoryOrder: CategoryType[] = ['sales', 'deposit', 'bill', 'receivable'];

  return (
    <PageLayout>
      {/* 페이지 헤더 */}
      <PageHeader
        title="미수금 현황"
        description="거래처별 월별 미수금 현황을 조회합니다."
        icon={FileText}
      />

      {/* 헤더 액션 (연도 선택, 버튼) */}
      <Card>
        <CardContent className="p-4">
          <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
            <div className="grid grid-cols-1 gap-3 sm:flex sm:items-center sm:gap-4">
              {/* 연도 선택 */}
              <div className="flex items-center gap-2">
                <span className="text-sm font-medium text-gray-700 shrink-0">연도</span>
                <Select
                  value={String(selectedYear)}
                  onValueChange={(value) => setSelectedYear(Number(value))}
                >
                  <SelectTrigger className="min-w-[100px] w-auto">
                    <SelectValue placeholder="연도 선택" />
                  </SelectTrigger>
                  <SelectContent>
                    {generateYearOptions().map((option) => (
                      <SelectItem key={option.value} value={String(option.value)}>
                        {option.label}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>

              {/* 정렬 선택 */}
              <div className="flex items-center gap-2">
                <span className="text-sm font-medium text-gray-700 shrink-0">정렬</span>
                <Select
                  value={sortOption}
                  onValueChange={(value) => setSortOption(value as SortOption)}
                >
                  <SelectTrigger className="min-w-[110px] w-auto">
                    <SelectValue placeholder="정렬 선택" />
                  </SelectTrigger>
                  <SelectContent>
                    {SORT_OPTIONS.map((option) => (
                      <SelectItem key={option.value} value={option.value}>
                        {option.label}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              </div>
            </div>
            <div className="flex flex-wrap items-center gap-2">
              <Button
                variant="outline"
                size="sm"
                onClick={loadData}
                disabled={isLoading}
              >
                {isLoading ? (
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                ) : (
                  <RefreshCw className="mr-2 h-4 w-4" />
                )}
                새로고침
              </Button>
              {canExport && (
                <Button
                  variant="outline"
                  size="sm"
                  onClick={handleExcelDownload}
                >
                  <Download className="mr-2 h-4 w-4" />
                  엑셀 다운로드
                </Button>
              )}
              <Button
                size="sm"
                onClick={handleSave}
                disabled={isPending || totalChangedCount === 0}
                className="bg-blue-500 hover:bg-blue-600 disabled:opacity-50"
              >
                {isPending ? (
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                ) : (
                  <Save className="mr-2 h-4 w-4" />
                )}
                저장 {totalChangedCount > 0 && `(${totalChangedCount})`}
              </Button>
            </div>
          </div>
        </CardContent>
      </Card>

      {/* 검색 */}
      <Card>
        <CardContent className="p-6">
          <SearchFilter
            searchValue={searchQuery}
            onSearchChange={setSearchQuery}
            searchPlaceholder="거래처 검색..."
            filterButton={false}
          />
        </CardContent>
      </Card>

      {/* 테이블 - xl 이상에서만 표시 */}
      <Card className="hidden xl:block">
        <CardContent className="pt-6">
          <div className="rounded-md border overflow-x-auto">
            <Table className="border-separate border-spacing-0" style={{ minWidth: `${200 + 70 + (monthCount * 100) + 120}px` }}>
              <TableHeader>
                <TableRow>
                  {/* 거래처/연체 - 왼쪽 고정 */}
                  <TableHead className="w-[140px] sm:w-[200px] min-w-[140px] sm:min-w-[200px] max-w-[140px] sm:max-w-[200px] sticky left-0 z-20 bg-white border-r border-gray-200">
                    거래처 / 연체
                  </TableHead>
                  {/* 구분 - sm 이상에서만 왼쪽 고정 */}
                  <TableHead className="w-[70px] min-w-[70px] text-center sm:sticky sm:left-[200px] z-20 bg-white border-r border-gray-200">
                    구분
                  </TableHead>
                  {/* 동적 월 레이블 - 스크롤 영역 */}
                  {monthLabels.map((month, idx) => (
                    <TableHead key={`${month}-${idx}`} className="w-[80px] min-w-[80px] text-right">
                      {month}
                    </TableHead>
                  ))}
                  {/* 합계 - sm 이상에서만 오른쪽 고정 */}
                  <TableHead className="w-[100px] min-w-[100px] text-right sm:sticky sm:right-0 z-20 bg-white sm:border-l border-gray-200">
                    합계
                  </TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {isLoading ? (
                  <TableRow>
                    <TableCell colSpan={monthCount + 3} className="h-24 text-center">
                      <div className="flex items-center justify-center gap-2">
                        <Loader2 className="h-5 w-5 animate-spin text-gray-400" />
                        <span className="text-gray-500">데이터를 불러오는 중...</span>
                      </div>
                    </TableCell>
                  </TableRow>
                ) : sortedData.length === 0 ? (
                  <TableRow>
                    <TableCell colSpan={monthCount + 3} className="h-24 text-center">
                      검색 결과가 없습니다.
                    </TableCell>
                  </TableRow>
                ) : (
                  sortedData.map((vendor) => {
                    const isOverdueRow = vendor.isOverdue;
                    const isHighlighted = highlightVendorId === vendor.id;
                    // 하이라이트 > 연체 > 기본 순으로 배경색 결정
                    const rowBgClass = isHighlighted
                      ? 'bg-yellow-100'
                      : isOverdueRow
                        ? 'bg-red-50'
                        : 'bg-white';

                    // 구분별 행 (매출, 입금, 어음, 미수금) + 메모 행 = 총 5개 행
                    const rows = [];

                    // 구분별 행 렌더링 (rowSpan 대신 각 행마다 개별 거래처 셀로 sticky 안정화)
                    categoryOrder.forEach((category, catIndex) => {
                      const categoryData = vendor.categories.find(c => c.category === category);
                      if (!categoryData) return;

                      rows.push(
                        <TableRow
                          key={`${vendor.id}-${category}`}
                          ref={catIndex === 0 && isHighlighted ? highlightRowRef : undefined}
                          className={`${catIndex === 0 ? 'border-t-2 border-gray-300' : ''} ${isHighlighted ? 'ring-2 ring-yellow-400 ring-inset' : ''}`}
                        >
                          {/* 거래처명 - 왼쪽 고정 (매 행마다 개별 셀, 첫 행만 내용 표시) */}
                          <TableCell
                            className={`font-medium border-r border-gray-200 sticky left-0 z-10 w-[140px] sm:w-[200px] min-w-[140px] sm:min-w-[200px] max-w-[140px] sm:max-w-[200px] overflow-hidden whitespace-normal ${rowBgClass} ${catIndex === 0 ? 'align-top pt-3' : 'p-0'}`}
                          >
                            {catIndex === 0 && (
                              <div className="flex flex-col gap-2 overflow-hidden">
                                <span className="text-sm line-clamp-2 break-words" title={vendor.vendorName}>{vendor.vendorName}</span>
                                <div className="flex items-center gap-2">
                                  <Switch
                                    checked={vendor.isOverdue}
                                    onCheckedChange={(checked) => handleOverdueToggle(vendor.id, checked)}
                                    className="data-[state=checked]:bg-red-500"
                                  />
                                  {vendor.isOverdue && (
                                    <span className="text-xs text-red-500 font-medium">연체</span>
                                  )}
                                </div>
                              </div>
                            )}
                          </TableCell>

                          {/* 구분 - sm 이상에서만 왼쪽 고정 */}
                          <TableCell className={`text-center border-r border-gray-200 text-sm sm:sticky sm:left-[200px] z-10 ${rowBgClass}`}>
                            {CATEGORY_LABELS[category]}
                          </TableCell>

                          {/* 월별 금액 - 스크롤 영역 */}
                          {categoryData.amounts.values.map((amount, monthIndex) => (
                            <TableCell
                              key={`${vendor.id}-${category}-${monthIndex}`}
                              className={`text-right text-sm border-r border-gray-200 ${rowBgClass}`}
                            >
                              {formatAmount(amount)}
                            </TableCell>
                          ))}

                          {/* 합계 - sm 이상에서만 오른쪽 고정 */}
                          <TableCell className={`text-right font-medium text-sm sm:sticky sm:right-0 z-10 sm:border-l border-gray-200 ${rowBgClass}`}>
                            {formatAmount(categoryData.amounts.total)}
                          </TableCell>
                        </TableRow>
                      );
                    });

                    // 메모 행 추가 (마지막 행)
                    const isMemoExpanded = expandedMemos.has(vendor.id);
                    rows.push(
                      <TableRow key={`${vendor.id}-memo`}>
                        {/* 거래처명 셀 (빈 셀 - 시각적 병합 유지) */}
                        <TableCell className={`border-r border-gray-200 sticky left-0 z-10 w-[140px] sm:w-[200px] min-w-[140px] sm:min-w-[200px] max-w-[140px] sm:max-w-[200px] overflow-hidden p-0 ${rowBgClass}`} />

                        {/* 구분: 메모 + 접기/펼치기 버튼 */}
                        <TableCell className={`text-center border-r border-gray-200 text-sm sm:sticky sm:left-[200px] z-10 ${rowBgClass}`}>
                          <div className="flex items-center justify-center gap-1">
                            <span>메모</span>
                            <button
                              type="button"
                              onClick={() => toggleMemoExpand(vendor.id)}
                              className="p-0.5 hover:bg-gray-200 rounded"
                            >
                              {isMemoExpanded ? (
                                <ChevronUp className="h-4 w-4 text-gray-500" />
                              ) : (
                                <ChevronDown className="h-4 w-4 text-gray-500" />
                              )}
                            </button>
                          </div>
                        </TableCell>

                        {/* 메모 입력 - 모든 월 컬럼 + 합계 컬럼 병합 */}
                        <TableCell colSpan={monthCount + 1} className={`p-1 ${rowBgClass}`}>
                          <Textarea
                            value={vendor.memo}
                            onChange={(e) => handleMemoChange(vendor.id, e.target.value)}
                            placeholder="거래처 메모를 입력하세요..."
                            className="w-full text-sm resize-none transition-all !min-h-0 !py-1"
                            style={{
                              height: isMemoExpanded ? '72px' : '32px',
                              lineHeight: '24px',
                              overflowY: isMemoExpanded ? 'auto' : 'hidden',
                            }}
                          />
                        </TableCell>
                      </TableRow>
                    );

                    return rows;
                  })
                )}
              </TableBody>
              <TableFooter>
                <TableRow className="bg-gray-100 font-semibold border-t-2 border-gray-300">
                  {/* 합계 행 - 왼쪽 고정 */}
                  <TableCell className="border-r border-gray-200 sticky left-0 z-10 bg-gray-100">
                    합계
                  </TableCell>
                  <TableCell className="text-center border-r border-gray-200 sm:sticky sm:left-[200px] z-10 bg-gray-100">
                    미수금
                  </TableCell>
                  {/* 월별 합계 - 스크롤 영역 */}
                  {grandTotals.values.map((amount, idx) => (
                    <TableCell key={`total-${idx}`} className="text-right text-sm border-r border-gray-200">
                      {formatAmount(amount)}
                    </TableCell>
                  ))}
                  {/* 총합계 - sm 이상에서만 오른쪽 고정 */}
                  <TableCell className="text-right font-bold sm:sticky sm:right-0 z-10 bg-gray-100 sm:border-l border-gray-200">
                    {formatAmount(grandTotals.total)}
                  </TableCell>
                </TableRow>
              </TableFooter>
            </Table>
          </div>
        </CardContent>
      </Card>

      {/* 모바일 카드 뷰 - xl 미만에서만 표시 */}
      <div className="xl:hidden space-y-3">
        {isLoading ? (
          <Card>
            <CardContent className="py-8">
              <div className="flex items-center justify-center gap-2">
                <Loader2 className="h-5 w-5 animate-spin text-gray-400" />
                <span className="text-gray-500">데이터를 불러오는 중...</span>
              </div>
            </CardContent>
          </Card>
        ) : sortedData.length === 0 ? (
          <Card>
            <CardContent className="py-8 text-center text-gray-500">
              검색 결과가 없습니다.
            </CardContent>
          </Card>
        ) : (
          <>
            {sortedData.map((vendor) => {
              const salesCat = vendor.categories.find(c => c.category === 'sales');
              const depositCat = vendor.categories.find(c => c.category === 'deposit');
              const billCat = vendor.categories.find(c => c.category === 'bill');
              const receivableCat = vendor.categories.find(c => c.category === 'receivable');
              const isHighlighted = highlightVendorId === vendor.id;

              return (
                <MobileCard
                  key={vendor.id}
                  title={vendor.vendorName}
                  className={
                    isHighlighted
                      ? 'border-yellow-400 bg-yellow-50'
                      : vendor.isOverdue
                        ? 'border-red-300 bg-red-50/50'
                        : undefined
                  }
                  headerBadges={
                    vendor.isOverdue ? (
                      <Badge variant="destructive" className="text-xs">연체</Badge>
                    ) : null
                  }
                  subtitle={`미수금 합계: ${formatNumber(receivableCat?.amounts.total || 0)}원`}
                  collapsible
                  defaultExpanded={false}
                  infoGrid={
                    <div className="space-y-2 text-sm">
                      {[
                        { label: '매출', value: salesCat?.amounts.total || 0 },
                        { label: '입금', value: depositCat?.amounts.total || 0 },
                        { label: '어음', value: billCat?.amounts.total || 0 },
                        { label: '미수금', value: receivableCat?.amounts.total || 0, bold: true },
                      ].map((item) => (
                        <div key={item.label} className="flex justify-between items-center">
                          <span className="text-muted-foreground">{item.label}</span>
                          <span className={item.bold ? 'font-bold' : 'font-medium'}>
                            {formatNumber(item.value)}원
                          </span>
                        </div>
                      ))}
                    </div>
                  }
                  bottomContent={
                    <div className="space-y-3" onClick={(e) => e.stopPropagation()}>
                      <div className="flex items-center gap-2">
                        <Switch
                          checked={vendor.isOverdue}
                          onCheckedChange={(checked) => handleOverdueToggle(vendor.id, checked)}
                          className="data-[state=checked]:bg-red-500"
                        />
                        <span className="text-sm">연체 설정</span>
                      </div>
                      <Textarea
                        value={vendor.memo}
                        onChange={(e) => handleMemoChange(vendor.id, e.target.value)}
                        placeholder="거래처 메모를 입력하세요..."
                        className="text-sm resize-none"
                        rows={2}
                      />
                    </div>
                  }
                />
              );
            })}

            {/* 합계 카드 */}
            <Card className="bg-gray-50 border-gray-300">
              <CardContent className="p-4">
                <div className="flex justify-between items-center">
                  <span className="font-semibold text-sm">미수금 총합계</span>
                  <span className="font-bold text-lg">{formatNumber(grandTotals.total)}원</span>
                </div>
              </CardContent>
            </Card>
          </>
        )}
      </div>
    </PageLayout>
  );
}