@extends('layouts.app')

@section('title', '카드 사용내역')

@section('content')
<div id="ecard-root"></div>
@endsection

@push('scripts')
@include('partials.react-cdn')

<script type="text/babel">
    const { useState, useEffect, useRef, useCallback } = React;

    // API Routes
    const API = {
        cards: '{{ route("barobill.ecard.cards") }}',
        transactions: '{{ route("barobill.ecard.transactions") }}',
        accountCodes: '{{ route("barobill.ecard.account-codes") }}',
        save: '{{ route("barobill.ecard.save") }}',
        export: '{{ route("barobill.ecard.export") }}',
        splits: '{{ route("barobill.ecard.splits") }}',
        saveSplits: '{{ route("barobill.ecard.splits.save") }}',
        deleteSplits: '{{ route("barobill.ecard.splits.delete") }}',
        manualStore: '{{ route("barobill.ecard.manual.store") }}',
        manualUpdate: '{{ route("barobill.ecard.manual.update", ":id") }}',
        manualDestroy: '{{ route("barobill.ecard.manual.destroy", ":id") }}',
        hide: '{{ route("barobill.ecard.hide") }}',
        restore: '{{ route("barobill.ecard.restore") }}',
        hidden: '{{ route("barobill.ecard.hidden") }}',
        journalStore: '{{ route("barobill.ecard.journal.store") }}',
        journalShow: '{{ route("barobill.ecard.journal.show") }}',
        journalDelete: '/barobill/ecard/journal/',
        journalStatuses: '{{ route("barobill.ecard.journal.statuses") }}',
    };

    const CSRF_TOKEN = '{{ csrf_token() }}';

    // 로컬 타임존 기준 날짜 포맷 (YYYY-MM-DD) - 한국 시간 기준
    const formatLocalDate = (date) => {
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0');
        const day = String(date.getDate()).padStart(2, '0');
        return `${year}-${month}-${day}`;
    };

    // 날짜 유틸리티 함수
    const getMonthDates = (offset = 0) => {
        const now = new Date();
        const today = formatLocalDate(now);
        const year = now.getFullYear();
        const month = now.getMonth() + offset;
        const firstDay = new Date(year, month, 1);
        const lastDay = new Date(year, month + 1, 0);

        // 종료일: 이번달이면 오늘, 지난달이면 그 달의 마지막 날
        const lastDayStr = formatLocalDate(lastDay);
        const endDate = offset >= 0 && lastDayStr > today ? today : lastDayStr;

        return {
            from: formatLocalDate(firstDay),
            to: endDate
        };
    };

    // Toast 알림 (전역 showToast 사용)
    const notify = (message, type = 'info') => {
        if (typeof window.showToast === 'function') {
            window.showToast(message, type);
        } else {
            alert(message);
        }
    };

    // CompactStat Component (계좌입출금 스타일 통계 배지)
    const CompactStat = ({ label, value, color = 'stone' }) => {
        const colorClasses = {
            purple: 'text-purple-600',
            green: 'text-green-600',
            red: 'text-red-600',
            stone: 'text-stone-700'
        };
        return (
            <div className="flex items-center gap-3 px-6 py-4 bg-white rounded-xl border border-gray-200 shadow-sm">
                <span className="text-base text-stone-500 font-medium">{label}</span>
                <span className={`text-xl font-bold ${colorClasses[color]}`}>{value}</span>
            </div>
        );
    };

    // AccountCodeSelect Component (검색 가능한 드롭다운)
    const AccountCodeSelect = ({ value, onChange, accountCodes }) => {
        const [isOpen, setIsOpen] = useState(false);
        const [search, setSearch] = useState('');
        const [highlightIndex, setHighlightIndex] = useState(-1);
        const containerRef = useRef(null);
        const listRef = useRef(null);

        // 선택된 값의 표시 텍스트
        const selectedItem = accountCodes.find(c => c.code === value);
        const displayText = selectedItem ? `${selectedItem.code} ${selectedItem.name}` : '';

        // 검색 필터링
        const filteredCodes = accountCodes.filter(code => {
            if (!search) return true;
            const searchLower = search.toLowerCase();
            return code.code.toLowerCase().includes(searchLower) ||
                   code.name.toLowerCase().includes(searchLower);
        });

        // 검색어 변경 시 하이라이트 초기화
        useEffect(() => {
            setHighlightIndex(-1);
        }, [search]);

        // 외부 클릭 시 닫기
        useEffect(() => {
            const handleClickOutside = (e) => {
                if (containerRef.current && !containerRef.current.contains(e.target)) {
                    setIsOpen(false);
                    setSearch('');
                    setHighlightIndex(-1);
                }
            };
            document.addEventListener('mousedown', handleClickOutside);
            return () => document.removeEventListener('mousedown', handleClickOutside);
        }, []);

        const handleSelect = (code) => {
            const selected = accountCodes.find(c => c.code === code.code);
            onChange(code.code, selected?.name || '');
            setIsOpen(false);
            setSearch('');
            setHighlightIndex(-1);
        };

        const handleClear = (e) => {
            e.stopPropagation();
            onChange('', '');
            setSearch('');
            setHighlightIndex(-1);
        };

        // 키보드 네비게이션
        const handleKeyDown = (e) => {
            const maxIndex = Math.min(filteredCodes.length, 50) - 1;

            if (e.key === 'ArrowDown') {
                e.preventDefault();
                const newIndex = highlightIndex < maxIndex ? highlightIndex + 1 : 0;
                setHighlightIndex(newIndex);
                setTimeout(() => {
                    if (listRef.current && listRef.current.children[newIndex]) {
                        listRef.current.children[newIndex].scrollIntoView({ block: 'nearest' });
                    }
                }, 0);
            } else if (e.key === 'ArrowUp') {
                e.preventDefault();
                const newIndex = highlightIndex > 0 ? highlightIndex - 1 : maxIndex;
                setHighlightIndex(newIndex);
                setTimeout(() => {
                    if (listRef.current && listRef.current.children[newIndex]) {
                        listRef.current.children[newIndex].scrollIntoView({ block: 'nearest' });
                    }
                }, 0);
            } else if (e.key === 'Enter' && filteredCodes.length > 0) {
                e.preventDefault();
                const selectIndex = highlightIndex >= 0 ? highlightIndex : 0;
                handleSelect(filteredCodes[selectIndex]);
            } else if (e.key === 'Escape') {
                setIsOpen(false);
                setSearch('');
                setHighlightIndex(-1);
            }
        };

        return (
            <div ref={containerRef} className="relative">
                {/* 선택 버튼 */}
                <div
                    onClick={() => setIsOpen(!isOpen)}
                    className={`w-full px-2 py-1 text-xs border rounded cursor-pointer flex items-center justify-between gap-1 ${
                        isOpen ? 'border-purple-500 ring-2 ring-purple-500' : 'border-stone-200'
                    } bg-white`}
                >
                    <span className={displayText ? 'text-stone-900' : 'text-stone-400'}>
                        {displayText || '선택'}
                    </span>
                    <div className="flex items-center gap-1">
                        {value && (
                            <button
                                onClick={handleClear}
                                className="text-stone-400 hover:text-stone-600"
                            >
                                <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
                                </svg>
                            </button>
                        )}
                        <svg className={`w-3 h-3 text-stone-400 transition-transform ${isOpen ? 'rotate-180' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7" />
                        </svg>
                    </div>
                </div>

                {/* 드롭다운 */}
                {isOpen && (
                    <div className="absolute z-[9999] mt-1 w-48 bg-white border border-stone-200 rounded-lg shadow-xl">
                        {/* 검색 입력 */}
                        <div className="p-2 border-b border-stone-100">
                            <input
                                type="text"
                                value={search}
                                onChange={(e) => setSearch(e.target.value)}
                                onKeyDown={handleKeyDown}
                                placeholder="코드 또는 이름 검색..."
                                className="w-full px-2 py-1 text-xs border border-stone-200 rounded focus:ring-1 focus:ring-purple-500 outline-none"
                                autoFocus
                            />
                        </div>
                        {/* 옵션 목록 */}
                        <div ref={listRef} className="max-h-48 overflow-y-auto">
                            {filteredCodes.length === 0 ? (
                                <div className="px-3 py-2 text-xs text-stone-400 text-center">
                                    검색 결과 없음
                                </div>
                            ) : (
                                filteredCodes.slice(0, 50).map((code, index) => (
                                    <div
                                        key={code.code}
                                        onClick={() => handleSelect(code)}
                                        className={`px-3 py-1.5 text-xs cursor-pointer ${
                                            index === highlightIndex
                                                ? 'bg-purple-600 text-white font-semibold'
                                                : value === code.code
                                                    ? 'bg-purple-100 text-purple-700'
                                                    : 'text-stone-700 hover:bg-purple-50'
                                        }`}
                                    >
                                        <span className={`font-mono ${index === highlightIndex ? 'text-white' : 'text-purple-600'}`}>{code.code}</span>
                                        <span className="ml-1">{code.name}</span>
                                    </div>
                                ))
                            )}
                            {filteredCodes.length > 50 && (
                                <div className="px-3 py-1 text-xs text-stone-400 text-center border-t">
                                    +{filteredCodes.length - 50}개 더 있음
                                </div>
                            )}
                        </div>
                    </div>
                )}
            </div>
        );
    };

    // SplitModal Component - 분리 모달
    const SplitModal = ({ isOpen, onClose, log, accountCodes, onSave, onReset, splits: existingSplits }) => {
        const [splits, setSplits] = useState([]);
        const [saving, setSaving] = useState(false);
        const [resetting, setResetting] = useState(false);

        useEffect(() => {
            if (isOpen && log) {
                const defaultDeductionType = log.deductionType || (log.merchantBizNum ? 'deductible' : 'non_deductible');
                if (existingSplits && existingSplits.length > 0) {
                    // 기존 분리 로드
                    setSplits(existingSplits.map(s => {
                        const hasSupplyTax = s.split_supply_amount !== null && s.split_supply_amount !== undefined;
                        return {
                            supplyAmount: hasSupplyTax ? parseFloat(s.split_supply_amount) : parseFloat(s.split_amount || s.amount || 0),
                            tax: hasSupplyTax ? parseFloat(s.split_tax || 0) : 0,
                            accountCode: s.account_code || s.accountCode || '',
                            accountName: s.account_name || s.accountName || '',
                            deductionType: s.deduction_type || s.deductionType || defaultDeductionType,
                            evidenceName: s.evidence_name || s.evidenceName || log.evidenceName || log.merchantName || '',
                            description: s.description || log.description || log.merchantBizType || log.memo || '',
                            memo: s.memo || ''
                        };
                    }));
                } else {
                    // 새 분리: 원본의 공급가액/세액로 1개 행 생성
                    const origSupply = log.effectiveSupplyAmount ?? ((log.approvalAmount || 0) - (log.tax || 0));
                    const origTax = log.effectiveTax ?? (log.tax || 0);
                    setSplits([{
                        supplyAmount: origSupply,
                        tax: origTax,
                        accountCode: log.accountCode || '',
                        accountName: log.accountName || '',
                        deductionType: defaultDeductionType,
                        evidenceName: log.evidenceName || log.merchantName || '',
                        description: log.description || log.merchantBizType || log.memo || '',
                        memo: ''
                    }]);
                }
            }
        }, [isOpen, log, existingSplits]);

        if (!isOpen || !log) return null;

        const originalAmount = log.approvalAmount || 0;
        // 합계금액 = sum(공급가액 + 세액)
        const splitTotal = splits.reduce((sum, s) => sum + (parseFloat(s.supplyAmount) || 0) + (parseFloat(s.tax) || 0), 0);
        const isValid = Math.abs(originalAmount - splitTotal) < 0.01;

        const addSplit = () => {
            const remaining = originalAmount - splitTotal;
            const defaultDeductionType = log.deductionType || (log.merchantBizNum ? 'deductible' : 'non_deductible');
            setSplits([...splits, {
                supplyAmount: remaining > 0 ? remaining : 0,
                tax: 0,
                accountCode: '',
                accountName: '',
                deductionType: defaultDeductionType,
                evidenceName: log.evidenceName || log.merchantName || '',
                description: log.description || log.merchantBizType || log.memo || '',
                memo: ''
            }]);
        };

        const removeSplit = (index) => {
            if (splits.length <= 1) return;
            setSplits(splits.filter((_, i) => i !== index));
        };

        const updateSplit = (index, updates) => {
            const newSplits = [...splits];
            newSplits[index] = { ...newSplits[index], ...updates };
            setSplits(newSplits);
        };

        const handleSave = async () => {
            if (!isValid) {
                notify('분리 합계금액이 원본 금액과 일치하지 않습니다.', 'error');
                return;
            }
            setSaving(true);
            await onSave(log, splits);
            setSaving(false);
            onClose();
        };

        const handleReset = async () => {
            if (!confirm('분리를 삭제하고 원본 거래로 복구하시겠습니까?')) {
                return;
            }
            setResetting(true);
            await onReset(log);
            setResetting(false);
            onClose();
        };

        const formatCurrency = (val) => new Intl.NumberFormat('ko-KR').format(val || 0);

        // 금액 입력 포맷팅 (콤마 추가)
        const formatAmountInput = (value) => {
            if (!value && value !== 0) return '';
            return new Intl.NumberFormat('ko-KR').format(value);
        };

        // 금액 입력값 파싱 (콤마 제거)
        const parseAmountInput = (value) => {
            const cleaned = String(value).replace(/[^0-9.-]/g, '');
            return parseFloat(cleaned) || 0;
        };

        return (
            <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
                <div className="bg-white rounded-xl shadow-xl w-full max-w-2xl max-h-[90vh] overflow-hidden">
                    <div className="p-6 border-b border-stone-200">
                        <div className="flex items-center justify-between">
                            <h3 className="text-lg font-bold text-stone-900">거래 분리</h3>
                            <button onClick={onClose} className="text-stone-400 hover:text-stone-600">
                                <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
                                </svg>
                            </button>
                        </div>
                        <div className="mt-3 p-3 bg-stone-50 rounded-lg text-sm">
                            <div className="flex justify-between mb-1">
                                <span className="text-stone-500">가맹점</span>
                                <span className="font-medium">{log.merchantName}</span>
                            </div>
                            <div className="flex justify-between mb-1">
                                <span className="text-stone-500">사용일시</span>
                                <span className="font-medium">{log.useDateTime}</span>
                            </div>
                            <div className="flex justify-between mb-1">
                                <span className="text-stone-500">공급가액</span>
                                <span className="font-medium">{formatCurrency(log.effectiveSupplyAmount ?? ((log.approvalAmount || 0) - (log.tax || 0)))}원</span>
                            </div>
                            <div className="flex justify-between mb-1">
                                <span className="text-stone-500">세액</span>
                                <span className="font-medium">{formatCurrency(log.effectiveTax ?? (log.tax || 0))}원</span>
                            </div>
                            <div className="flex justify-between">
                                <span className="text-stone-500">합계금액</span>
                                <span className="font-bold text-purple-600">{formatCurrency(originalAmount)}원</span>
                            </div>
                        </div>
                    </div>

                    <div className="p-6 overflow-y-auto" style={ {maxHeight: '400px'} }>
                        <div className="space-y-3">
                            {splits.map((split, index) => {
                                const rowTotal = (parseFloat(split.supplyAmount) || 0) + (parseFloat(split.tax) || 0);
                                return (
                                <div key={index} className="flex items-start gap-3 p-3 bg-stone-50 rounded-lg">
                                    <div className="flex-1 grid grid-cols-3 gap-3">
                                        <div>
                                            <label className="block text-xs text-stone-500 mb-1">공급가액</label>
                                            <input
                                                type="text"
                                                value={formatAmountInput(split.supplyAmount)}
                                                onChange={(e) => updateSplit(index, { supplyAmount: parseAmountInput(e.target.value) })}
                                                className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm text-right focus:ring-2 focus:ring-purple-500 outline-none"
                                                placeholder="0"
                                            />
                                        </div>
                                        <div>
                                            <label className="block text-xs text-stone-500 mb-1">세액</label>
                                            <input
                                                type="text"
                                                value={formatAmountInput(split.tax)}
                                                onChange={(e) => updateSplit(index, { tax: parseAmountInput(e.target.value) })}
                                                className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm text-right focus:ring-2 focus:ring-purple-500 outline-none"
                                                placeholder="0"
                                            />
                                        </div>
                                        <div>
                                            <label className="block text-xs text-stone-500 mb-1">합계금액</label>
                                            <div className="px-3 py-2 bg-stone-100 rounded-lg text-sm text-right font-medium text-purple-700">
                                                {formatCurrency(rowTotal)}원
                                            </div>
                                        </div>
                                        <div>
                                            <label className="block text-xs text-stone-500 mb-1">계정과목</label>
                                            <AccountCodeSelect
                                                value={split.accountCode}
                                                onChange={(code, name) => updateSplit(index, { accountCode: code, accountName: name })}
                                                accountCodes={accountCodes}
                                            />
                                        </div>
                                        <div>
                                            <label className="block text-xs text-stone-500 mb-1">공제</label>
                                            <select
                                                value={split.deductionType || 'deductible'}
                                                onChange={(e) => updateSplit(index, { deductionType: e.target.value })}
                                                className={`w-full px-3 py-2 border border-stone-200 rounded-lg text-sm font-bold focus:ring-2 focus:ring-purple-500 outline-none ${
                                                    split.deductionType === 'non_deductible'
                                                        ? 'bg-red-500 text-white'
                                                        : 'bg-green-100 text-green-700'
                                                }`}
                                            >
                                                <option value="deductible">공제</option>
                                                <option value="non_deductible">불공</option>
                                            </select>
                                        </div>
                                        <div>
                                            <label className="block text-xs text-stone-500 mb-1">증빙/판매자상호</label>
                                            <input
                                                type="text"
                                                value={split.evidenceName || ''}
                                                onChange={(e) => updateSplit(index, { evidenceName: e.target.value })}
                                                placeholder="판매자상호"
                                                className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                            />
                                        </div>
                                        <div>
                                            <label className="block text-xs text-stone-500 mb-1">내역</label>
                                            <input
                                                type="text"
                                                value={split.description || ''}
                                                onChange={(e) => updateSplit(index, { description: e.target.value })}
                                                placeholder="내역"
                                                className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                            />
                                        </div>
                                        <div className="col-span-2">
                                            <label className="block text-xs text-stone-500 mb-1">메모</label>
                                            <input
                                                type="text"
                                                value={split.memo}
                                                onChange={(e) => updateSplit(index, { memo: e.target.value })}
                                                placeholder="분리 메모 (선택)"
                                                className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                            />
                                        </div>
                                    </div>
                                    <button
                                        onClick={() => removeSplit(index)}
                                        disabled={splits.length <= 1}
                                        className="mt-6 p-2 text-red-500 hover:bg-red-50 rounded-lg disabled:opacity-30 disabled:cursor-not-allowed"
                                    >
                                        <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M20 12H4" />
                                        </svg>
                                    </button>
                                </div>
                                );
                            })}
                        </div>

                        <button
                            onClick={addSplit}
                            className="mt-3 w-full py-2 border-2 border-dashed border-stone-300 text-stone-500 rounded-lg hover:border-purple-400 hover:text-purple-600 transition-colors flex items-center justify-center gap-2"
                        >
                            <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 4v16m8-8H4" />
                            </svg>
                            분리 항목 추가
                        </button>
                    </div>

                    <div className="p-6 border-t border-stone-200 bg-stone-50">
                        <div className="flex items-center justify-between mb-4">
                            <span className="text-sm text-stone-500">분리 합계</span>
                            <span className={`font-bold ${isValid ? 'text-green-600' : 'text-red-600'}`}>
                                {formatCurrency(splitTotal)}원
                                {!isValid && (
                                    <span className="ml-2 text-xs font-normal">
                                        (차이: {formatCurrency(originalAmount - splitTotal)}원)
                                    </span>
                                )}
                            </span>
                        </div>
                        <div className="flex gap-3">
                            {existingSplits && existingSplits.length > 0 && (
                                <button
                                    onClick={handleReset}
                                    disabled={resetting}
                                    className="py-2 px-4 border border-red-300 text-red-600 rounded-lg hover:bg-red-50 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                                >
                                    {resetting ? '복구 중...' : '분리 복구'}
                                </button>
                            )}
                            <button
                                onClick={onClose}
                                className="flex-1 py-2 border border-stone-300 text-stone-700 rounded-lg hover:bg-stone-100 transition-colors"
                            >
                                취소
                            </button>
                            <button
                                onClick={handleSave}
                                disabled={!isValid || saving}
                                className="flex-1 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                            >
                                {saving ? '저장 중...' : '분리 저장'}
                            </button>
                        </div>
                    </div>
                </div>
            </div>
        );
    };

    // ============================================
    // TradingPartnerSelect - 거래처 드롭다운
    // ============================================
    const TradingPartnerSelect = ({ value, valueName, onChange }) => {
        const [isOpen, setIsOpen] = useState(false);
        const [search, setSearch] = useState('');
        const [partners, setPartners] = useState([]);
        const [loading, setLoading] = useState(false);
        const [highlightIndex, setHighlightIndex] = useState(-1);
        const [dropdownStyle, setDropdownStyle] = useState({});
        const containerRef = useRef(null);
        const triggerRef = useRef(null);
        const listRef = useRef(null);
        const dropdownRef = useRef(null);

        const displayText = valueName || '';

        // 드롭다운 위치 계산 (fixed 기반, 위/아래 자동 판단)
        const calcDropdownPos = () => {
            if (!triggerRef.current) return;
            const rect = triggerRef.current.getBoundingClientRect();
            const dropdownH = 260; // 예상 드롭다운 높이
            const spaceBelow = window.innerHeight - rect.bottom;
            const openUp = spaceBelow < dropdownH && rect.top > dropdownH;
            if (openUp) {
                setDropdownStyle({ position: 'fixed', bottom: window.innerHeight - rect.top + 4, left: rect.left, width: 288, zIndex: 9999 });
            } else {
                setDropdownStyle({ position: 'fixed', top: rect.bottom + 4, left: rect.left, width: 288, zIndex: 9999 });
            }
        };

        const toggleOpen = () => {
            if (!isOpen) { calcDropdownPos(); }
            setIsOpen(!isOpen);
        };

        // 검색어 변경 시 API 조회
        useEffect(() => {
            if (!isOpen) return;
            setLoading(true);
            const url = search
                ? `/finance/journal-entries/trading-partners?search=${encodeURIComponent(search)}`
                : '/finance/journal-entries/trading-partners';
            fetch(url)
                .then(res => res.json())
                .then(data => { if (data.success) setPartners(data.data || []); })
                .catch(() => {})
                .finally(() => setLoading(false));
        }, [isOpen, search]);

        useEffect(() => { setHighlightIndex(-1); }, [search]);

        // 스크롤/리사이즈 시 위치 재계산
        useEffect(() => {
            if (!isOpen) return;
            const handleScroll = () => calcDropdownPos();
            const scrollParent = triggerRef.current?.closest('.overflow-y-auto');
            if (scrollParent) scrollParent.addEventListener('scroll', handleScroll);
            window.addEventListener('resize', handleScroll);
            return () => {
                if (scrollParent) scrollParent.removeEventListener('scroll', handleScroll);
                window.removeEventListener('resize', handleScroll);
            };
        }, [isOpen]);

        useEffect(() => {
            const handleClickOutside = (e) => {
                if (containerRef.current && !containerRef.current.contains(e.target) &&
                    dropdownRef.current && !dropdownRef.current.contains(e.target)) {
                    setIsOpen(false); setSearch(''); setHighlightIndex(-1);
                }
            };
            document.addEventListener('mousedown', handleClickOutside);
            return () => document.removeEventListener('mousedown', handleClickOutside);
        }, []);

        const handleSelect = (partner) => {
            onChange(partner.id, partner.name);
            setIsOpen(false); setSearch(''); setHighlightIndex(-1);
        };
        const handleClear = (e) => { e.stopPropagation(); onChange(null, ''); setSearch(''); };

        const handleKeyDown = (e) => {
            const maxIdx = partners.length - 1;
            if (e.key === 'ArrowDown') { e.preventDefault(); setHighlightIndex(prev => prev < maxIdx ? prev + 1 : 0); }
            else if (e.key === 'ArrowUp') { e.preventDefault(); setHighlightIndex(prev => prev > 0 ? prev - 1 : maxIdx); }
            else if (e.key === 'Enter' && partners.length > 0) { e.preventDefault(); handleSelect(partners[highlightIndex >= 0 ? highlightIndex : 0]); }
            else if (e.key === 'Escape') { setIsOpen(false); setSearch(''); setHighlightIndex(-1); }
        };

        return (
            <div ref={containerRef} className="relative">
                <div ref={triggerRef} onClick={toggleOpen}
                    className={`w-full px-3 py-1.5 text-sm border rounded-lg cursor-pointer flex items-center justify-between gap-1 ${isOpen ? 'border-purple-500 ring-1 ring-purple-500' : 'border-stone-200'} bg-white`}>
                    <span className={displayText ? 'text-stone-900 truncate' : 'text-stone-400 text-xs'}>{displayText || '거래처 선택'}</span>
                    <div className="flex items-center gap-1 flex-shrink-0">
                        {value && <button onClick={handleClear} className="text-stone-400 hover:text-stone-600">
                            <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" /></svg>
                        </button>}
                        <svg className={`w-3 h-3 text-stone-400 transition-transform ${isOpen ? 'rotate-180' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7" /></svg>
                    </div>
                </div>
                {isOpen && ReactDOM.createPortal(
                    <div ref={dropdownRef} style={dropdownStyle} className="bg-white border border-stone-200 rounded-lg shadow-lg">
                        <div className="p-2 border-b border-stone-100">
                            <input type="text" value={search} onChange={(e) => setSearch(e.target.value)} onKeyDown={handleKeyDown}
                                placeholder="거래처명 또는 사업자번호 검색..." className="w-full px-2.5 py-1.5 text-sm border border-stone-200 rounded-lg focus:ring-1 focus:ring-purple-500 outline-none" autoFocus />
                        </div>
                        <div ref={listRef} className="max-h-48 overflow-y-auto">
                            {loading ? (
                                <div className="px-3 py-2 text-xs text-stone-400 text-center">검색 중...</div>
                            ) : partners.length === 0 ? (
                                <div className="px-3 py-2 text-xs text-stone-400 text-center">검색 결과 없음</div>
                            ) : partners.map((p, index) => (
                                <div key={p.id} onClick={() => handleSelect(p)}
                                    className={`px-3 py-1.5 text-sm cursor-pointer ${index === highlightIndex ? 'bg-purple-600 text-white font-semibold' : value === p.id ? 'bg-purple-100 text-purple-700' : 'text-stone-700 hover:bg-purple-50'}`}>
                                    <span className="font-medium">{p.name}</span>
                                    {p.biz_no && <span className={`ml-1 text-xs ${index === highlightIndex ? 'text-purple-100' : 'text-stone-400'}`}>({p.biz_no})</span>}
                                </div>
                            ))}
                        </div>
                    </div>,
                    document.body
                )}
            </div>
        );
    };

    // ============================================
    // CardJournalModal - 복식부기 분개 모달
    // ============================================
    const CardJournalModal = ({ isOpen, onClose, onSave, onDelete, log, accountCodes = [] }) => {
        const formatCurrency = (val) => new Intl.NumberFormat('ko-KR').format(val || 0);
        const formatAmountInput = (val) => { const n = String(val).replace(/[^\d]/g, ''); return n ? Number(n).toLocaleString() : ''; };
        const parseAmountInput = (val) => parseInt(String(val).replace(/[^\d]/g, ''), 10) || 0;

        if (!log) return null;

        const supplyAmount = Math.round(log.effectiveSupplyAmount ?? ((log.approvalAmount || 0) - (log.tax || 0)));
        const taxAmount = Math.round(log.effectiveTax ?? (log.tax || 0));
        const totalAmount = supplyAmount + taxAmount;
        const isDeductible = (log.deductionType || 'non_deductible') === 'deductible';

        const uniqueKey = log.uniqueKey || `${log.cardNum}|${log.useDt}|${log.approvalNum}|${Math.floor(log.approvalAmount)}`;

        // 기본 분개 라인
        const getDefaultLines = () => {
            // 단일 split 분개 (분리 항목별 개별 분개)
            const singleSplit = log._split;
            if (singleSplit) {
                const splitSupply = Math.round(parseFloat(singleSplit.split_supply_amount ?? singleSplit.supplyAmount ?? singleSplit.split_amount ?? singleSplit.amount ?? 0));
                const splitTax = Math.round(parseFloat(singleSplit.split_tax ?? singleSplit.tax ?? 0));
                const splitDeductionType = singleSplit.deduction_type || singleSplit.deductionType || 'non_deductible';
                const splitAccountCode = singleSplit.account_code || singleSplit.accountCode || '826';
                const splitAccountName = singleSplit.account_name || singleSplit.accountName || '잡비';

                const lines = [];
                let totalDebitSum = 0;

                if (splitDeductionType === 'deductible') {
                    // 공제: 비용 계정 = 공급가액, 부가세대급금 = 세액
                    lines.push({
                        dc_type: 'debit', account_code: splitAccountCode, account_name: splitAccountName,
                        debit_amount: splitSupply, credit_amount: 0,
                        trading_partner_id: null, trading_partner_name: '', description: singleSplit.memo || ''
                    });
                    totalDebitSum += splitSupply;
                    if (splitTax > 0) {
                        lines.push({
                            dc_type: 'debit', account_code: '135', account_name: '부가세대급금',
                            debit_amount: splitTax, credit_amount: 0,
                            trading_partner_id: null, trading_partner_name: '', description: ''
                        });
                        totalDebitSum += splitTax;
                    }
                } else {
                    // 불공제: 비용 계정 = 공급가액 + 세액
                    const combined = splitSupply + splitTax;
                    lines.push({
                        dc_type: 'debit', account_code: splitAccountCode, account_name: splitAccountName,
                        debit_amount: combined, credit_amount: 0,
                        trading_partner_id: null, trading_partner_name: '', description: singleSplit.memo || ''
                    });
                    totalDebitSum += combined;
                }

                // 대변: 미지급비용 = 합계
                lines.push({
                    dc_type: 'credit', account_code: '205', account_name: '미지급비용',
                    debit_amount: 0, credit_amount: totalDebitSum,
                    trading_partner_id: null, trading_partner_name: '', description: ''
                });

                return lines;
            }

            // splits가 없으면 기존 로직 (원본 금액 기반, 분리 없는 거래용)
            const expenseCode = log.accountCode || '826';
            const expenseName = log.accountName || '잡비';

            if (isDeductible) {
                return [
                    { dc_type: 'debit', account_code: expenseCode, account_name: expenseName, debit_amount: supplyAmount, credit_amount: 0, trading_partner_id: null, trading_partner_name: '', description: '' },
                    { dc_type: 'debit', account_code: '135', account_name: '부가세대급금', debit_amount: taxAmount, credit_amount: 0, trading_partner_id: null, trading_partner_name: '', description: '' },
                    { dc_type: 'credit', account_code: '205', account_name: '미지급비용', debit_amount: 0, credit_amount: totalAmount, trading_partner_id: null, trading_partner_name: '', description: '' },
                ];
            } else {
                return [
                    { dc_type: 'debit', account_code: expenseCode, account_name: expenseName, debit_amount: totalAmount, credit_amount: 0, trading_partner_id: null, trading_partner_name: '', description: '' },
                    { dc_type: 'credit', account_code: '205', account_name: '미지급비용', debit_amount: 0, credit_amount: totalAmount, trading_partner_id: null, trading_partner_name: '', description: '' },
                ];
            }
        };

        const [lines, setLines] = useState(getDefaultLines());
        const [saving, setSaving] = useState(false);
        const [loadingJournal, setLoadingJournal] = useState(false);
        const [isEditMode, setIsEditMode] = useState(false);
        const [journalId, setJournalId] = useState(null);
        const [amountMismatch, setAmountMismatch] = useState(null);

        // 카드 기준 금액 계산 (split 또는 원본)
        const getExpectedCardAmount = () => {
            if (log._split) {
                const splitSupply = Math.round(parseFloat(log._split.split_supply_amount ?? log._split.supplyAmount ?? log._split.split_amount ?? log._split.amount ?? 0));
                const splitTax = Math.round(parseFloat(log._split.split_tax ?? log._split.tax ?? 0));
                const splitDeductionType = log._split.deduction_type || log._split.deductionType || 'non_deductible';
                if (splitDeductionType === 'deductible') {
                    return splitSupply + splitTax;
                }
                return splitSupply + splitTax;
            }
            return totalAmount;
        };

        // 기존 분개 로드
        useEffect(() => {
            if (!isOpen || !log) return;
            setAmountMismatch(null);

            const checkMismatch = (journalLines) => {
                const journalTotal = journalLines.reduce((sum, l) => sum + (parseInt(l.debit_amount) || 0), 0);
                const expectedTotal = getExpectedCardAmount();
                if (Math.abs(journalTotal - expectedTotal) > 0) {
                    setAmountMismatch({ journalTotal, expectedTotal, diff: expectedTotal - journalTotal });
                }
            };

            if (log._journalData) {
                const mappedLines = log._journalData.lines.map(l => ({
                    dc_type: l.dc_type,
                    account_code: l.account_code,
                    account_name: l.account_name,
                    debit_amount: l.debit_amount,
                    credit_amount: l.credit_amount,
                    trading_partner_id: l.trading_partner_id || null,
                    trading_partner_name: l.trading_partner_name || '',
                    description: l.description || '',
                }));
                setLines(mappedLines);
                setIsEditMode(true);
                setJournalId(log._journalData.id);
                checkMismatch(mappedLines);
            } else if (log._hasJournal) {
                setLoadingJournal(true);
                fetch(`${API.journalShow}?source_key=${encodeURIComponent(uniqueKey)}`)
                    .then(res => res.json())
                    .then(data => {
                        if (data.success && data.data) {
                            const mappedLines = data.data.lines.map(l => ({
                                dc_type: l.dc_type,
                                account_code: l.account_code,
                                account_name: l.account_name,
                                debit_amount: l.debit_amount,
                                credit_amount: l.credit_amount,
                                trading_partner_id: l.trading_partner_id || null,
                                trading_partner_name: l.trading_partner_name || '',
                                description: l.description || '',
                            }));
                            setLines(mappedLines);
                            setIsEditMode(true);
                            setJournalId(data.data.id);
                            checkMismatch(mappedLines);
                        } else {
                            setLines(getDefaultLines());
                            setIsEditMode(false);
                            setJournalId(null);
                        }
                    })
                    .catch(err => console.error('분개 로드 오류:', err))
                    .finally(() => setLoadingJournal(false));
            } else {
                setLines(getDefaultLines());
                setIsEditMode(false);
                setJournalId(null);
            }
        }, [isOpen, log]);

        // 카드 데이터 기준으로 분개 라인 갱신
        const handleSyncFromCard = () => {
            setLines(getDefaultLines());
            setAmountMismatch(null);
        };

        const updateLine = (idx, field, value) => {
            setLines(prev => prev.map((l, i) => i === idx ? { ...l, [field]: value } : l));
        };

        const addLine = () => {
            setLines(prev => [...prev, { dc_type: 'debit', account_code: '', account_name: '', debit_amount: 0, credit_amount: 0, trading_partner_id: null, trading_partner_name: '', description: '' }]);
        };

        const removeLine = (idx) => {
            if (lines.length <= 2) return;
            setLines(prev => prev.filter((_, i) => i !== idx));
        };

        const totalDebit = lines.reduce((sum, l) => sum + (parseInt(l.debit_amount) || 0), 0);
        const totalCredit = lines.reduce((sum, l) => sum + (parseInt(l.credit_amount) || 0), 0);
        const isBalanced = totalDebit === totalCredit && totalDebit > 0;

        const toggleDcType = (idx) => {
            setLines(prev => prev.map((l, i) => {
                if (i !== idx) return l;
                const newType = l.dc_type === 'debit' ? 'credit' : 'debit';
                return { ...l, dc_type: newType, debit_amount: l.credit_amount, credit_amount: l.debit_amount };
            }));
        };

        const handleSubmit = async () => {
            const emptyLine = lines.find(l => !l.account_code || !l.account_name);
            if (emptyLine) {
                notify('모든 분개 라인의 계정과목을 선택해주세요.', 'warning');
                return;
            }
            if (!isBalanced) {
                notify('차변과 대변의 합계가 일치하지 않습니다.', 'warning');
                return;
            }
            setSaving(true);

            // entry_date: useDt에서 YYYY-MM-DD 추출
            const useDt = log.useDt || '';
            const entryDate = useDt.length >= 8
                ? `${useDt.substring(0,4)}-${useDt.substring(4,6)}-${useDt.substring(6,8)}`
                : new Date().toISOString().substring(0,10);

            await onSave({
                source_key: uniqueKey,
                entry_date: entryDate,
                description: `${log.merchantName || ''} 카드결제`,
                lines,
            });
            setSaving(false);
        };

        const handleDelete = async () => {
            if (!journalId) return;
            if (!confirm('분개를 삭제하시겠습니까?')) return;
            setSaving(true);
            await onDelete(journalId);
            setSaving(false);
        };

        if (!isOpen) return null;

        return (
            <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
                <div className="bg-white rounded-2xl shadow-2xl w-full max-w-3xl mx-4 max-h-[90vh] overflow-hidden">
                    <div className="p-6 border-b border-stone-100 flex items-center justify-between">
                        <h3 className="text-lg font-bold text-stone-900">
                            {isEditMode ? '분개 수정' : '분개 생성'}
                        </h3>
                        <button onClick={onClose} className="p-2 hover:bg-stone-100 rounded-lg transition-colors">
                            <svg className="w-5 h-5 text-stone-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
                            </svg>
                        </button>
                    </div>
                    <div className="p-6 overflow-y-auto max-h-[65vh] space-y-5">
                        {/* 카드 거래 정보 */}
                        <div className="bg-stone-50 rounded-xl p-4">
                            <h4 className="text-sm font-semibold text-stone-700 mb-3">카드 거래 정보</h4>
                            <div className="grid grid-cols-2 md:grid-cols-4 gap-3 text-sm">
                                <div><span className="text-stone-500">가맹점: </span><span className="font-medium">{log.merchantName || '-'}</span></div>
                                <div><span className="text-stone-500">사용일시: </span><span className="font-medium">{log.useDateTime || '-'}</span></div>
                                <div><span className="text-stone-500">공급가액: </span><span className="font-medium">{formatCurrency(supplyAmount)}</span></div>
                                <div><span className="text-stone-500">세액: </span><span className="font-medium">{formatCurrency(taxAmount)}</span></div>
                            </div>
                            {log._split && (
                                <div className="mt-3">
                                    <div className="flex items-center gap-2 mb-2">
                                        <span className="inline-flex items-center px-2.5 py-1 bg-amber-100 text-amber-700 rounded-lg text-xs font-bold">
                                            분리 항목 분개
                                        </span>
                                        {isEditMode && (
                                            <span className="text-xs text-stone-400">저장된 분개가 있어 참고용으로 표시됩니다</span>
                                        )}
                                    </div>
                                    <div className="grid grid-cols-2 md:grid-cols-4 gap-3 text-sm bg-amber-50 rounded-lg p-3">
                                        <div><span className="text-stone-500">계정: </span><span className="font-medium">{log._split.account_name || log._split.accountName || '미지정'}</span></div>
                                        <div><span className="text-stone-500">공제: </span><span className="font-medium">{(log._split.deduction_type || log._split.deductionType) === 'deductible' ? '공제' : '불공제'}</span></div>
                                        <div><span className="text-stone-500">공급가액: </span><span className="font-medium">{formatCurrency(Math.round(parseFloat(log._split.split_supply_amount ?? log._split.supplyAmount ?? log._split.split_amount ?? log._split.amount ?? 0)))}</span></div>
                                        <div><span className="text-stone-500">세액: </span><span className="font-medium">{formatCurrency(Math.round(parseFloat(log._split.split_tax ?? log._split.tax ?? 0)))}</span></div>
                                    </div>
                                </div>
                            )}
                        </div>

                        {/* 카드 금액 ↔ 분개 금액 불일치 경고 */}
                        {amountMismatch && (
                            <div className="bg-red-50 border border-red-200 rounded-xl p-4">
                                <div className="flex items-start gap-3">
                                    <svg className="w-5 h-5 text-red-500 mt-0.5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z" />
                                    </svg>
                                    <div className="flex-1">
                                        <p className="text-sm font-bold text-red-700">카드 금액과 분개 금액이 일치하지 않습니다</p>
                                        <div className="mt-2 grid grid-cols-3 gap-2 text-sm">
                                            <div><span className="text-red-500">카드 금액: </span><span className="font-bold text-red-700">{formatCurrency(amountMismatch.expectedTotal)}원</span></div>
                                            <div><span className="text-red-500">분개 금액: </span><span className="font-bold text-red-700">{formatCurrency(amountMismatch.journalTotal)}원</span></div>
                                            <div><span className="text-red-500">차이: </span><span className="font-bold text-red-700">{formatCurrency(Math.abs(amountMismatch.diff))}원</span></div>
                                        </div>
                                        <button
                                            onClick={handleSyncFromCard}
                                            className="mt-3 px-4 py-1.5 bg-red-600 text-white rounded-lg text-xs font-bold hover:bg-red-700 transition-colors"
                                        >
                                            카드 데이터로 갱신
                                        </button>
                                    </div>
                                </div>
                            </div>
                        )}

                        {loadingJournal ? (
                            <div className="flex items-center justify-center py-8">
                                <div className="animate-spin rounded-full h-6 w-6 border-2 border-purple-600 border-t-transparent"></div>
                                <span className="ml-2 text-sm text-stone-500">분개 데이터 로딩중...</span>
                            </div>
                        ) : (
                            <div>
                                <h4 className="text-sm font-semibold text-stone-700 mb-3">분개 내역</h4>
                                <table className="w-full text-sm border border-stone-200 rounded-lg overflow-hidden">
                                    <thead>
                                        <tr className="bg-stone-100">
                                            <th className="px-3 py-2 text-center text-xs font-semibold text-stone-600 border-b border-stone-200 w-16">차/대</th>
                                            <th className="px-3 py-2 text-center text-xs font-semibold text-stone-600 border-b border-stone-200">계정과목</th>
                                            <th className="px-3 py-2 text-center text-xs font-semibold text-stone-600 border-b border-stone-200">거래처</th>
                                            <th className="px-3 py-2 text-center text-xs font-semibold text-stone-600 border-b border-stone-200 w-32">차변금액</th>
                                            <th className="px-3 py-2 text-center text-xs font-semibold text-stone-600 border-b border-stone-200 w-32">대변금액</th>
                                            <th className="px-3 py-2 text-center text-xs font-semibold text-stone-600 border-b border-stone-200 w-10"></th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        {lines.map((line, idx) => (
                                            <tr key={idx} className="border-b border-stone-100">
                                                <td className="px-3 py-2 text-center">
                                                    <button
                                                        type="button"
                                                        onClick={() => toggleDcType(idx)}
                                                        className={`px-2 py-0.5 rounded text-xs font-medium cursor-pointer hover:opacity-80 transition-opacity ${line.dc_type === 'debit' ? 'bg-blue-100 text-blue-700' : 'bg-red-100 text-red-700'}`}
                                                        title="클릭하여 차변/대변 전환"
                                                    >
                                                        {line.dc_type === 'debit' ? '차변' : '대변'}
                                                    </button>
                                                </td>
                                                <td className="px-3 py-2">
                                                    <AccountCodeSelect
                                                        value={line.account_code}
                                                        onChange={(code, name) => {
                                                            setLines(prev => prev.map((l, i) => i === idx ? { ...l, account_code: code, account_name: name } : l));
                                                        }}
                                                        accountCodes={accountCodes}
                                                    />
                                                </td>
                                                <td className="px-3 py-2">
                                                    <TradingPartnerSelect
                                                        value={line.trading_partner_id}
                                                        valueName={line.trading_partner_name}
                                                        onChange={(id, name) => {
                                                            setLines(prev => prev.map((l, i) => i === idx ? { ...l, trading_partner_id: id, trading_partner_name: name } : l));
                                                        }}
                                                    />
                                                </td>
                                                <td className="px-3 py-2">
                                                    <input
                                                        type="text"
                                                        value={formatAmountInput(line.debit_amount)}
                                                        onChange={(e) => updateLine(idx, 'debit_amount', parseAmountInput(e.target.value))}
                                                        className="w-full px-2 py-1 border border-stone-200 rounded text-sm text-right focus:ring-1 focus:ring-purple-500 outline-none"
                                                    />
                                                </td>
                                                <td className="px-3 py-2">
                                                    <input
                                                        type="text"
                                                        value={formatAmountInput(line.credit_amount)}
                                                        onChange={(e) => updateLine(idx, 'credit_amount', parseAmountInput(e.target.value))}
                                                        className="w-full px-2 py-1 border border-stone-200 rounded text-sm text-right focus:ring-1 focus:ring-purple-500 outline-none"
                                                    />
                                                </td>
                                                <td className="px-3 py-2 text-center">
                                                    <button
                                                        onClick={() => removeLine(idx)}
                                                        disabled={lines.length <= 2}
                                                        className="text-red-400 hover:text-red-600 disabled:opacity-30 disabled:cursor-not-allowed"
                                                    >
                                                        <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M20 12H4" />
                                                        </svg>
                                                    </button>
                                                </td>
                                            </tr>
                                        ))}
                                        {/* 합계 */}
                                        <tr className={`font-bold ${isBalanced ? 'bg-green-50' : 'bg-red-50'}`}>
                                            <td colSpan="3" className="px-3 py-2 text-center text-sm">합계</td>
                                            <td className="px-3 py-2 text-right text-sm">{formatCurrency(totalDebit)}</td>
                                            <td className="px-3 py-2 text-right text-sm">{formatCurrency(totalCredit)}</td>
                                            <td></td>
                                        </tr>
                                    </tbody>
                                </table>
                                {!isBalanced && (
                                    <p className="text-red-500 text-xs mt-2">차변과 대변의 합계가 일치하지 않습니다. (차이: {formatCurrency(Math.abs(totalDebit - totalCredit))})</p>
                                )}

                                {/* 행 추가 버튼 */}
                                <button
                                    onClick={addLine}
                                    className="mt-3 w-full py-2 border-2 border-dashed border-stone-300 text-stone-500 rounded-lg hover:border-purple-400 hover:text-purple-600 transition-colors flex items-center justify-center gap-2 text-sm"
                                >
                                    <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 4v16m8-8H4" />
                                    </svg>
                                    행 추가
                                </button>
                            </div>
                        )}
                    </div>
                    <div className="p-4 border-t border-stone-100 flex justify-between">
                        <div>
                            {isEditMode && journalId && (
                                <button
                                    onClick={handleDelete}
                                    disabled={saving}
                                    className="px-4 py-2 bg-red-50 text-red-600 rounded-lg text-sm font-medium hover:bg-red-100 transition-colors disabled:opacity-50"
                                >
                                    분개 삭제
                                </button>
                            )}
                        </div>
                        <div className="flex gap-3">
                            <button onClick={onClose} className="px-4 py-2 bg-stone-100 text-stone-700 rounded-lg text-sm font-medium hover:bg-stone-200 transition-colors">
                                취소
                            </button>
                            <button
                                onClick={handleSubmit}
                                disabled={saving || !isBalanced || loadingJournal}
                                className="px-6 py-2 bg-purple-600 text-white rounded-lg text-sm font-medium hover:bg-purple-700 transition-colors disabled:opacity-50 flex items-center gap-2"
                            >
                                {saving && <div className="animate-spin rounded-full h-4 w-4 border-2 border-white border-t-transparent"></div>}
                                {isEditMode ? '분개 수정' : '분개 저장'}
                            </button>
                        </div>
                    </div>
                </div>
            </div>
        );
    };

    // 카드사 코드 목록
    const CARD_COMPANIES = [
        { code: '01', name: '비씨' },
        { code: '02', name: 'KB국민' },
        { code: '03', name: '하나(외환)' },
        { code: '04', name: '삼성' },
        { code: '06', name: '신한' },
        { code: '07', name: '현대' },
        { code: '08', name: '롯데' },
        { code: '11', name: 'NH농협' },
        { code: '12', name: '수협' },
        { code: '13', name: '씨티' },
        { code: '14', name: '우리' },
        { code: '15', name: '광주' },
        { code: '16', name: '전북' },
        { code: '21', name: '하나' },
        { code: '22', name: '제주' },
        { code: '23', name: 'SC제일' },
        { code: '25', name: 'KDB산업' },
        { code: '26', name: 'IBK기업' },
        { code: '27', name: '새마을금고' },
        { code: '28', name: '신협' },
        { code: '29', name: '저축은행' },
        { code: '30', name: '우체국' },
        { code: '31', name: '카카오뱅크' },
        { code: '32', name: 'K뱅크' },
        { code: '33', name: '토스뱅크' },
    ];

    // ManualEntryModal Component - 수동입력 모달
    const ManualEntryModal = ({ isOpen, onClose, onSave, editData, accountCodes, cards }) => {
        const [form, setForm] = useState({});
        const [saving, setSaving] = useState(false);

        const isEditMode = !!editData;

        useEffect(() => {
            if (isOpen) {
                if (editData) {
                    // 수정 모드: 기존 데이터로 채움
                    const isRegisteredCard = cards.some(c => c.cardNum === editData.cardNum);
                    setForm({
                        card_company: editData.cardCompany || '',
                        card_num: editData.cardNum || '',
                        _manualCard: !isRegisteredCard,
                        use_date: editData.useDate || '',
                        use_time: editData.useTime || '',
                        approval_num: editData.approvalNum || '',
                        approval_type: editData.approvalType || '1',
                        approval_amount: editData.effectiveSupplyAmount || 0,
                        tax: editData.effectiveTax || 0,
                        merchant_name: editData.merchantName || '',
                        merchant_biz_num: editData.merchantBizNum || '',
                        deduction_type: editData.deductionType || 'deductible',
                        account_code: editData.accountCode || '',
                        account_name: editData.accountName || '',
                        evidence_name: editData.evidenceName || '',
                        description: editData.description || '',
                        memo: editData.memo || '',
                    });
                } else {
                    // 신규 모드: 빈 폼
                    const today = new Date();
                    const todayStr = today.getFullYear() +
                        String(today.getMonth() + 1).padStart(2, '0') +
                        String(today.getDate()).padStart(2, '0');
                    setForm({
                        card_company: '',
                        card_num: '',
                        _manualCard: false,
                        use_date: todayStr,
                        use_time: '',
                        approval_num: '',
                        approval_type: '1',
                        approval_amount: 0,
                        tax: 0,
                        merchant_name: '',
                        merchant_biz_num: '',
                        deduction_type: 'deductible',
                        account_code: '',
                        account_name: '',
                        evidence_name: '',
                        description: '',
                        memo: '',
                    });
                }
            }
        }, [isOpen, editData]);

        if (!isOpen) return null;

        const updateField = (field, value) => {
            setForm(prev => ({ ...prev, [field]: value }));
        };

        const handleSubmit = async () => {
            if (!form.card_company || !form.card_num || !form.use_date || !form.approval_type || form.approval_amount === '' || form.tax === '') {
                notify('필수 항목을 모두 입력해주세요.', 'error');
                return;
            }
            setSaving(true);
            await onSave(form, editData?.dbId);
            setSaving(false);
        };

        // use_date 표시용 포맷 (YYYYMMDD -> YYYY-MM-DD)
        const formatDateForInput = (val) => {
            if (!val || val.length !== 8) return val;
            return val.substring(0, 4) + '-' + val.substring(4, 6) + '-' + val.substring(6, 8);
        };
        const parseDateFromInput = (val) => val.replace(/-/g, '');

        // use_time 표시용 포맷 (HHMMSS -> HH:MM)
        const formatTimeForInput = (val) => {
            if (!val) return '';
            const clean = val.replace(/:/g, '');
            if (clean.length >= 4) return clean.substring(0, 2) + ':' + clean.substring(2, 4);
            return val;
        };
        const parseTimeFromInput = (val) => {
            const clean = val.replace(/:/g, '');
            return clean.padEnd(6, '0').substring(0, 6);
        };

        const formatCurrency = (val) => new Intl.NumberFormat('ko-KR').format(val || 0);
        const parseCurrency = (val) => parseFloat(String(val).replace(/[^0-9.-]/g, '')) || 0;

        return (
            <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
                <div className="bg-white rounded-xl shadow-xl w-full max-w-2xl max-h-[90vh] overflow-hidden">
                    <div className="p-6 border-b border-stone-200">
                        <div className="flex items-center justify-between">
                            <h3 className="text-lg font-bold text-stone-900">
                                {isEditMode ? '수동 거래 수정' : '수동 거래 입력'}
                            </h3>
                            <button onClick={onClose} className="text-stone-400 hover:text-stone-600">
                                <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
                                </svg>
                            </button>
                        </div>
                    </div>

                    <div className="p-6 overflow-y-auto" style={ {maxHeight: '60vh'} }>
                        <div className="grid grid-cols-2 gap-4">
                            {/* 카드 선택 */}
                            <div className="col-span-2">
                                <label className="block text-sm font-medium text-stone-700 mb-1">카드 선택 <span className="text-red-500">*</span></label>
                                <select
                                    value={form.card_num ? `${form.card_company}|${form.card_num}` : ''}
                                    onChange={(e) => {
                                        const val = e.target.value;
                                        if (val === '__manual__') {
                                            updateField('card_company', '');
                                            updateField('card_num', '');
                                            updateField('_manualCard', true);
                                        } else if (val) {
                                            const [company, ...numParts] = val.split('|');
                                            const cardNum = numParts.join('|');
                                            const card = cards.find(c => c.cardNum === cardNum);
                                            updateField('card_company', company || (card?.cardCompany || ''));
                                            updateField('card_num', cardNum);
                                            updateField('_manualCard', false);
                                        } else {
                                            updateField('card_company', '');
                                            updateField('card_num', '');
                                            updateField('_manualCard', false);
                                        }
                                    }}
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                >
                                    <option value="">-- 카드를 선택하세요 --</option>
                                    {cards.map(card => (
                                        <option key={card.cardNum} value={`${card.cardCompany}|${card.cardNum}`}>
                                            {card.cardBrand} ****{card.cardNum.slice(-4)} {card.alias ? `(${card.alias})` : ''} [{card.cardNum}]
                                        </option>
                                    ))}
                                    <option value="__manual__">직접 입력</option>
                                </select>
                            </div>
                            {/* 직접 입력 모드일 때만 표시 */}
                            {form._manualCard && (
                                <>
                                    <div>
                                        <label className="block text-sm font-medium text-stone-700 mb-1">카드사 <span className="text-red-500">*</span></label>
                                        <select
                                            value={form.card_company}
                                            onChange={(e) => updateField('card_company', e.target.value)}
                                            className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                        >
                                            <option value="">선택</option>
                                            {CARD_COMPANIES.map(c => (
                                                <option key={c.code} value={c.code}>{c.name}</option>
                                            ))}
                                        </select>
                                    </div>
                                    <div>
                                        <label className="block text-sm font-medium text-stone-700 mb-1">카드번호 <span className="text-red-500">*</span></label>
                                        <input
                                            type="text"
                                            value={form.card_num}
                                            onChange={(e) => updateField('card_num', e.target.value)}
                                            className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                            placeholder="카드번호 입력"
                                        />
                                    </div>
                                </>
                            )}
                            {/* 사용일 */}
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">사용일 <span className="text-red-500">*</span></label>
                                <input
                                    type="date"
                                    value={formatDateForInput(form.use_date)}
                                    onChange={(e) => updateField('use_date', parseDateFromInput(e.target.value))}
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                />
                            </div>
                            {/* 사용시간 */}
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">사용시간</label>
                                <input
                                    type="time"
                                    value={formatTimeForInput(form.use_time)}
                                    onChange={(e) => updateField('use_time', parseTimeFromInput(e.target.value))}
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                />
                            </div>
                            {/* 승인번호 */}
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">승인번호</label>
                                <input
                                    type="text"
                                    value={form.approval_num}
                                    onChange={(e) => updateField('approval_num', e.target.value)}
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                    placeholder="승인번호"
                                />
                            </div>
                            {/* 승인유형 */}
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">승인유형 <span className="text-red-500">*</span></label>
                                <div className="flex gap-4 mt-2">
                                    <label className="flex items-center gap-2 cursor-pointer">
                                        <input
                                            type="radio"
                                            value="1"
                                            checked={form.approval_type === '1'}
                                            onChange={(e) => updateField('approval_type', e.target.value)}
                                            className="text-purple-600 focus:ring-purple-500"
                                        />
                                        <span className="text-sm">승인</span>
                                    </label>
                                    <label className="flex items-center gap-2 cursor-pointer">
                                        <input
                                            type="radio"
                                            value="2"
                                            checked={form.approval_type === '2'}
                                            onChange={(e) => updateField('approval_type', e.target.value)}
                                            className="text-red-600 focus:ring-red-500"
                                        />
                                        <span className="text-sm">취소</span>
                                    </label>
                                </div>
                            </div>
                            {/* 공급가액 */}
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">공급가액 <span className="text-red-500">*</span></label>
                                <input
                                    type="text"
                                    value={formatCurrency(form.approval_amount)}
                                    onChange={(e) => {
                                        const val = parseCurrency(e.target.value);
                                        updateField('approval_amount', val);
                                    }}
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm text-right focus:ring-2 focus:ring-purple-500 outline-none"
                                    placeholder="0"
                                />
                            </div>
                            {/* 세액 */}
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">세액 <span className="text-red-500">*</span></label>
                                <input
                                    type="text"
                                    value={formatCurrency(form.tax)}
                                    onChange={(e) => {
                                        const val = parseCurrency(e.target.value);
                                        updateField('tax', val);
                                    }}
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm text-right focus:ring-2 focus:ring-purple-500 outline-none"
                                    placeholder="0"
                                />
                            </div>
                            {/* 가맹점명 */}
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">가맹점명</label>
                                <input
                                    type="text"
                                    value={form.merchant_name}
                                    onChange={(e) => updateField('merchant_name', e.target.value)}
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                    placeholder="가맹점명"
                                />
                            </div>
                            {/* 사업자번호 */}
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">사업자번호</label>
                                <input
                                    type="text"
                                    value={form.merchant_biz_num}
                                    onChange={(e) => updateField('merchant_biz_num', e.target.value)}
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                    placeholder="000-00-00000"
                                />
                            </div>
                            {/* 공제여부 */}
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">공제여부 <span className="text-red-500">*</span></label>
                                <select
                                    value={form.deduction_type}
                                    onChange={(e) => updateField('deduction_type', e.target.value)}
                                    className={`w-full px-3 py-2 border border-stone-200 rounded-lg text-sm font-bold focus:ring-2 focus:ring-purple-500 outline-none ${
                                        form.deduction_type === 'non_deductible'
                                            ? 'bg-red-500 text-white'
                                            : 'bg-green-100 text-green-700'
                                    }`}
                                >
                                    <option value="deductible">공제</option>
                                    <option value="non_deductible">불공</option>
                                </select>
                            </div>
                            {/* 계정과목 */}
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">계정과목</label>
                                <AccountCodeSelect
                                    value={form.account_code}
                                    onChange={(code, name) => {
                                        updateField('account_code', code);
                                        updateField('account_name', name);
                                    }}
                                    accountCodes={accountCodes}
                                />
                            </div>
                            {/* 증빙/판매자상호 */}
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">증빙/판매자상호</label>
                                <input
                                    type="text"
                                    value={form.evidence_name}
                                    onChange={(e) => updateField('evidence_name', e.target.value)}
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                    placeholder="증빙/판매자상호"
                                />
                            </div>
                            {/* 내역 */}
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">내역</label>
                                <input
                                    type="text"
                                    value={form.description}
                                    onChange={(e) => updateField('description', e.target.value)}
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                    placeholder="내역"
                                />
                            </div>
                            {/* 메모 */}
                            <div className="col-span-2">
                                <label className="block text-sm font-medium text-stone-700 mb-1">메모</label>
                                <input
                                    type="text"
                                    value={form.memo}
                                    onChange={(e) => updateField('memo', e.target.value)}
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                    placeholder="메모 (선택)"
                                />
                            </div>
                        </div>

                        {/* 합계 금액 표시 */}
                        <div className="mt-4 p-3 bg-purple-50 rounded-lg">
                            <div className="flex justify-between text-sm">
                                <span className="text-stone-600">합계 금액 (공급가액 + 세액)</span>
                                <span className="font-bold text-purple-700">
                                    {new Intl.NumberFormat('ko-KR').format((parseFloat(form.approval_amount) || 0) + (parseFloat(form.tax) || 0))}원
                                </span>
                            </div>
                        </div>
                    </div>

                    <div className="p-6 border-t border-stone-200 bg-stone-50 flex gap-3">
                        <button
                            onClick={onClose}
                            className="flex-1 py-2 border border-stone-300 text-stone-700 rounded-lg hover:bg-stone-100 transition-colors"
                        >
                            취소
                        </button>
                        <button
                            onClick={handleSubmit}
                            disabled={saving}
                            className="flex-1 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                        >
                            {saving ? '저장 중...' : (isEditMode ? '수정' : '등록')}
                        </button>
                    </div>
                </div>
            </div>
        );
    };

    // TransactionTable Component
    const TransactionTable = ({
        logs,
        loading,
        totalCount,
        accountCodes,
        onAccountCodeChange,
        onFieldChange,
        splits,
        onOpenSplitModal,
        onDeleteSplits,
        onManualEdit,
        onManualDelete,
        onHide,
        showHidden,
        hiddenLogs,
        onRestore,
        loadingHidden,
        journalMap,
        onOpenJournalModal,
    }) => {
        const formatCurrency = (val) => new Intl.NumberFormat('ko-KR').format(val || 0) + '원';

        if (loading) {
            return (
                <div className="flex items-center justify-center py-20">
                    <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-purple-600"></div>
                </div>
            );
        }

        return (
            <div className="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden min-h-[calc(100vh-200px)]">
                <div className="overflow-x-auto" style={ {minHeight: '500px', overflowY: 'auto'} }>
                    <table className="w-full text-left text-sm text-stone-600">
                        <thead className="bg-stone-50 text-xs uppercase font-medium text-stone-500 sticky top-0">
                            <tr>
                                <th className="px-3 py-4 bg-stone-50 w-10">분리</th>
                                <th className="px-3 py-4 bg-stone-50 w-10">분개</th>
                                <th className="px-4 py-4 bg-stone-50">사용일시</th>
                                <th className="px-4 py-4 bg-stone-50">카드정보</th>
                                <th className="px-4 py-4 bg-stone-50">공제</th>
                                <th className="px-4 py-4 bg-stone-50">사업자번호</th>
                                <th className="px-4 py-4 bg-stone-50">가맹점명</th>
                                <th className="px-4 py-4 bg-stone-50">증빙/판매자상호</th>
                                <th className="px-4 py-4 bg-stone-50 min-w-[250px]">내역</th>
                                <th className="px-4 py-4 text-right bg-stone-50">합계금액</th>
                                <th className="px-4 py-4 text-right bg-stone-50">공급가액</th>
                                <th className="px-4 py-4 text-right bg-stone-50">세액</th>
                                <th className="px-4 py-4 bg-stone-50 min-w-[150px]">계정과목</th>
                                <th className="px-3 py-4 bg-stone-50 w-16">관리</th>
                            </tr>
                        </thead>
                        <tbody className="divide-y divide-stone-100">
                            {logs.length === 0 ? (
                                <tr>
                                    <td colSpan="14" className="px-6 py-8 text-center text-stone-400">
                                        해당 기간에 조회된 카드 사용내역이 없습니다.
                                    </td>
                                </tr>
                            ) : (
                                logs.map((log, index) => {
                                    const uniqueKey = log.uniqueKey || `${log.cardNum}|${log.useDt}|${log.approvalNum}|${Math.floor(log.approvalAmount)}`;
                                    const logSplits = splits[uniqueKey] || [];
                                    const hasSplits = logSplits.length > 0;

                                    return (
                                        <React.Fragment key={index}>
                                            {/* 원본 거래 행 */}
                                            <tr className={`hover:bg-stone-50 transition-colors ${log.isSaved ? 'bg-purple-50/30' : ''} ${hasSplits ? 'bg-amber-50/50' : ''}`}>
                                                {/* 분리 열 */}
                                                <td className="px-3 py-3 text-center">
                                                    {(() => {
                                                        if (hasSplits) {
                                                            return (
                                                                <button
                                                                    onClick={() => onOpenSplitModal(log, uniqueKey, logSplits)}
                                                                    className="px-1.5 py-0.5 bg-amber-100 text-amber-700 rounded text-[10px] font-bold hover:bg-amber-200 transition-colors"
                                                                    title={`분리 ${logSplits.length}건 (클릭하여 수정)`}
                                                                >
                                                                    {logSplits.length}건
                                                                </button>
                                                            );
                                                        } else {
                                                            return (
                                                                <button
                                                                    onClick={() => onOpenSplitModal(log, uniqueKey, [])}
                                                                    className="p-1.5 text-amber-500 hover:bg-amber-100 rounded-lg transition-colors"
                                                                    title="금액 분리"
                                                                >
                                                                    <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 4v16m8-8H4" />
                                                                    </svg>
                                                                </button>
                                                            );
                                                        }
                                                    })()}
                                                </td>
                                                {/* 분개 열 */}
                                                <td className="px-3 py-3 text-center">
                                                    {(() => {
                                                        if (hasSplits) {
                                                            // 분리 항목별 분개 집계
                                                            const splitJournalCount = logSplits.filter(s => journalMap[`${uniqueKey}|split:${s.id}`]).length;
                                                            if (splitJournalCount === logSplits.length) {
                                                                return (
                                                                    <span className="px-1.5 py-0.5 bg-emerald-100 text-emerald-700 rounded text-[10px] font-bold">
                                                                        완료
                                                                    </span>
                                                                );
                                                            } else {
                                                                return (
                                                                    <span className={`text-[10px] font-bold ${splitJournalCount > 0 ? 'text-purple-600' : 'text-stone-400'}`}>
                                                                        {splitJournalCount}/{logSplits.length}
                                                                    </span>
                                                                );
                                                            }
                                                        }
                                                        const jInfo = journalMap[uniqueKey];
                                                        if (jInfo) {
                                                            return (
                                                                <button
                                                                    onClick={() => onOpenJournalModal(log, uniqueKey, true, logSplits)}
                                                                    className="px-1.5 py-0.5 bg-emerald-100 text-emerald-700 rounded text-[10px] font-bold hover:bg-emerald-200 transition-colors"
                                                                    title={`전표: ${jInfo.entry_no}`}
                                                                >
                                                                    완료
                                                                </button>
                                                            );
                                                        } else {
                                                            return (
                                                                <button
                                                                    onClick={() => onOpenJournalModal(log, uniqueKey, false, logSplits)}
                                                                    className="p-1.5 text-purple-500 hover:bg-purple-100 rounded-lg transition-colors"
                                                                    title="분개 추가"
                                                                >
                                                                    <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 4v16m8-8H4" />
                                                                    </svg>
                                                                </button>
                                                            );
                                                        }
                                                    })()}
                                                </td>
                                                <td className="px-4 py-3 whitespace-nowrap">
                                                    <div className="font-medium text-stone-900">{log.useDateTime || '-'}</div>
                                                    {log.isManual && (
                                                        <span className="inline-block px-1.5 py-0.5 bg-green-100 text-green-700 text-[10px] font-bold rounded mt-0.5">수동</span>
                                                    )}
                                                </td>
                                                <td className="px-4 py-3">
                                                    <div className="font-medium text-stone-900">{log.cardBrand}</div>
                                                    <div className="text-xs text-stone-400 font-mono">
                                                        {log.cardNum ? '****-' + log.cardNum.slice(-4) : '-'}
                                                    </div>
                                                </td>
                                                <td className="px-4 py-3 text-center">
                                                    {hasSplits ? (
                                                        <span className="text-stone-400 font-medium">-</span>
                                                    ) : (
                                                        <select
                                                            value={log.deductionType || (log.merchantBizNum ? 'deductible' : 'non_deductible')}
                                                            onChange={(e) => onFieldChange(index, 'deductionType', e.target.value)}
                                                            className={`px-4 py-1.5 pr-8 rounded text-sm font-bold border-0 cursor-pointer w-[100px] ${
                                                                (log.deductionType || (log.merchantBizNum ? 'deductible' : 'non_deductible')) === 'deductible'
                                                                    ? 'bg-green-100 text-green-700'
                                                                    : 'bg-red-500 text-white'
                                                            }`}
                                                        >
                                                            <option value="deductible">공제</option>
                                                            <option value="non_deductible">불공</option>
                                                        </select>
                                                    )}
                                                </td>
                                                <td className="px-4 py-3 text-xs text-stone-600 font-mono whitespace-nowrap">
                                                    {log.merchantBizNum || '-'}
                                                </td>
                                                <td className="px-4 py-3 text-sm text-stone-700 whitespace-nowrap">
                                                    {(() => {
                                                        const name = log.merchantName || '-';
                                                        if (name.length <= 6) return name;
                                                        return (
                                                            <span
                                                                className="cursor-pointer hover:text-purple-600"
                                                                title={name}
                                                                onClick={() => { window._merchantModal = name; window.dispatchEvent(new Event('showMerchantModal')); }}
                                                            >
                                                                {name.slice(0, 6)}...
                                                            </span>
                                                        );
                                                    })()}
                                                </td>
                                                <td className="px-4 py-3">
                                                    <input
                                                        type="text"
                                                        value={log.evidenceName ?? log.merchantName ?? ''}
                                                        onChange={(e) => onFieldChange(index, 'evidenceName', e.target.value)}
                                                        className="w-full px-2 py-1 text-sm border border-stone-200 rounded focus:outline-none focus:ring-1 focus:ring-purple-500 focus:border-purple-500"
                                                        placeholder="판매자상호"
                                                    />
                                                </td>
                                                <td className="px-4 py-3">
                                                    <input
                                                        type="text"
                                                        value={log.description ?? log.merchantBizType ?? log.memo ?? ''}
                                                        onChange={(e) => onFieldChange(index, 'description', e.target.value)}
                                                        className="w-full px-2 py-1 text-sm border border-stone-200 rounded focus:outline-none focus:ring-1 focus:ring-purple-500 focus:border-purple-500"
                                                        placeholder="내역"
                                                    />
                                                </td>
                                                <td className="px-4 py-3 text-right font-medium">
                                                    {(() => {
                                                        const effectiveSupply = log.effectiveSupplyAmount ?? ((log.approvalAmount || 0) - (log.tax || 0));
                                                        const effectiveTax = log.effectiveTax ?? (log.tax || 0);
                                                        const totalAmount = effectiveSupply + effectiveTax;
                                                        return (
                                                            <div>
                                                                <span className={log.approvalType === '1' ? 'text-purple-600' : 'text-red-600'}>
                                                                    {new Intl.NumberFormat('ko-KR').format(totalAmount)}원
                                                                </span>
                                                                {log.isAmountModified && totalAmount !== log.approvalAmount && (
                                                                    <div className="text-xs text-stone-400 line-through">{log.approvalAmountFormatted}원</div>
                                                                )}
                                                            </div>
                                                        );
                                                    })()}
                                                    {!hasSplits && journalMap[uniqueKey] && (
                                                        <div className="text-xs text-emerald-600 mt-1">{journalMap[uniqueKey].entry_no}</div>
                                                    )}
                                                    {hasSplits && (() => {
                                                        const splitJournalCount = logSplits.filter(s => journalMap[`${uniqueKey}|split:${s.id}`]).length;
                                                        if (splitJournalCount > 0) {
                                                            return <div className="text-xs text-emerald-600 mt-1">분개 {splitJournalCount}/{logSplits.length}</div>;
                                                        }
                                                        return <div className="text-xs text-amber-600 mt-1">분리됨({logSplits.length}건)</div>;
                                                    })()}
                                                </td>
                                                <td className={`px-4 py-3 text-right ${log.isAmountModified && log.modifiedSupplyAmount !== null ? 'bg-orange-50' : ''}`}>
                                                    {hasSplits ? (
                                                        <span className="text-stone-500">
                                                            {new Intl.NumberFormat('ko-KR').format(log.effectiveSupplyAmount ?? ((log.approvalAmount || 0) - (log.tax || 0)))}원
                                                        </span>
                                                    ) : (
                                                        <div>
                                                            <input
                                                                type="text"
                                                                value={new Intl.NumberFormat('ko-KR').format(log.effectiveSupplyAmount ?? ((log.approvalAmount || 0) - (log.tax || 0)))}
                                                                onChange={(e) => {
                                                                    const val = parseFloat(String(e.target.value).replace(/[^0-9.-]/g, '')) || 0;
                                                                    const originalSupply = (log.approvalAmount || 0) - (log.tax || 0);
                                                                    const isModified = Math.abs(val - originalSupply) > 0.01;
                                                                    onFieldChange(index, 'effectiveSupplyAmount', val);
                                                                    onFieldChange(index, 'modifiedSupplyAmount', isModified ? val : null);
                                                                    onFieldChange(index, 'isAmountModified', isModified || log.modifiedTax !== null);
                                                                }}
                                                                className={`w-full px-2 py-1 text-sm text-right border rounded focus:outline-none focus:ring-1 focus:ring-purple-500 focus:border-purple-500 ${
                                                                    log.modifiedSupplyAmount !== null ? 'border-orange-300 bg-orange-50' : 'border-stone-200'
                                                                }`}
                                                            />
                                                            {log.modifiedSupplyAmount !== null && (
                                                                <div className="text-xs text-stone-400 line-through mt-0.5">
                                                                    {new Intl.NumberFormat('ko-KR').format((log.approvalAmount || 0) - (log.tax || 0))}원
                                                                </div>
                                                            )}
                                                        </div>
                                                    )}
                                                </td>
                                                <td className={`px-4 py-3 text-right ${log.isAmountModified && log.modifiedTax !== null ? 'bg-orange-50' : ''}`}>
                                                    {hasSplits ? (
                                                        <span className="text-stone-500">
                                                            {new Intl.NumberFormat('ko-KR').format(log.effectiveTax ?? (log.tax || 0))}원
                                                        </span>
                                                    ) : (
                                                        <div>
                                                            <input
                                                                type="text"
                                                                value={new Intl.NumberFormat('ko-KR').format(log.effectiveTax ?? (log.tax || 0))}
                                                                onChange={(e) => {
                                                                    const val = parseFloat(String(e.target.value).replace(/[^0-9.-]/g, '')) || 0;
                                                                    const originalTax = log.tax || 0;
                                                                    const isModified = Math.abs(val - originalTax) > 0.01;
                                                                    onFieldChange(index, 'effectiveTax', val);
                                                                    onFieldChange(index, 'modifiedTax', isModified ? val : null);
                                                                    onFieldChange(index, 'isAmountModified', isModified || log.modifiedSupplyAmount !== null);
                                                                }}
                                                                className={`w-full px-2 py-1 text-sm text-right border rounded focus:outline-none focus:ring-1 focus:ring-purple-500 focus:border-purple-500 ${
                                                                    log.modifiedTax !== null ? 'border-orange-300 bg-orange-50' : 'border-stone-200'
                                                                }`}
                                                            />
                                                            {log.modifiedTax !== null && (
                                                                <div className="text-xs text-stone-400 line-through mt-0.5">
                                                                    {new Intl.NumberFormat('ko-KR').format(log.tax || 0)}원
                                                                </div>
                                                            )}
                                                        </div>
                                                    )}
                                                </td>
                                                <td className="px-4 py-3">
                                                    {!hasSplits && (
                                                        <>
                                                            <AccountCodeSelect
                                                                value={log.accountCode}
                                                                onChange={(code, name) => onAccountCodeChange(index, code, name)}
                                                                accountCodes={accountCodes}
                                                            />
                                                            {log.accountName && (
                                                                <div className="text-xs text-purple-600 mt-1">{log.accountName}</div>
                                                            )}
                                                        </>
                                                    )}
                                                    {hasSplits && (
                                                        <span className="text-xs text-amber-600">
                                                            분리됨 ({logSplits.length}건)
                                                        </span>
                                                    )}
                                                </td>
                                                <td className="px-3 py-3 text-center">
                                                    <div className="flex items-center gap-1 justify-center">
                                                        {log.isManual && (
                                                            <>
                                                                <button
                                                                    onClick={() => onManualEdit(log)}
                                                                    className="p-1 text-blue-500 hover:bg-blue-50 rounded transition-colors"
                                                                    title="수정"
                                                                >
                                                                    <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
                                                                    </svg>
                                                                </button>
                                                                <button
                                                                    onClick={() => onManualDelete(log.dbId)}
                                                                    className="p-1 text-red-500 hover:bg-red-50 rounded transition-colors"
                                                                    title="삭제"
                                                                >
                                                                    <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
                                                                    </svg>
                                                                </button>
                                                            </>
                                                        )}
                                                        <button
                                                            onClick={() => onHide(log, uniqueKey)}
                                                            className="p-1 text-stone-400 hover:text-red-500 hover:bg-red-50 rounded transition-colors"
                                                            title="숨기기"
                                                        >
                                                            <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
                                                            </svg>
                                                        </button>
                                                    </div>
                                                </td>
                                            </tr>
                                            {/* 분리 행들 */}
                                            {hasSplits && logSplits.map((split, splitIdx) => {
                                                const splitSupply = split.split_supply_amount !== null && split.split_supply_amount !== undefined
                                                    ? parseFloat(split.split_supply_amount)
                                                    : parseFloat(split.split_amount || split.amount || 0);
                                                const splitTax = split.split_tax !== null && split.split_tax !== undefined
                                                    ? parseFloat(split.split_tax)
                                                    : 0;
                                                const splitTotal = splitSupply + splitTax;
                                                return (
                                                <tr key={`${index}-split-${splitIdx}`} className="bg-amber-50/30 hover:bg-amber-100/30">
                                                    <td className="px-3 py-2 text-center">
                                                        <div className="w-4 h-4 border-l-2 border-b-2 border-amber-300 ml-2"></div>
                                                    </td>
                                                    <td className="px-3 py-2 text-center">
                                                        {(() => {
                                                            const splitSourceKey = `${uniqueKey}|split:${split.id}`;
                                                            const sjInfo = journalMap[splitSourceKey];
                                                            if (sjInfo) {
                                                                return (
                                                                    <button
                                                                        onClick={() => onOpenJournalModal(log, splitSourceKey, true, logSplits, split)}
                                                                        className="px-1.5 py-0.5 bg-emerald-100 text-emerald-700 rounded text-[10px] font-bold hover:bg-emerald-200 transition-colors"
                                                                        title={`전표: ${sjInfo.entry_no}`}
                                                                    >
                                                                        완료
                                                                    </button>
                                                                );
                                                            } else {
                                                                return (
                                                                    <button
                                                                        onClick={() => onOpenJournalModal(log, splitSourceKey, false, logSplits, split)}
                                                                        className="px-1.5 py-0.5 bg-purple-100 text-purple-700 rounded text-[10px] font-bold hover:bg-purple-200 transition-colors"
                                                                        title="분리 항목 분개"
                                                                    >
                                                                        분개
                                                                    </button>
                                                                );
                                                            }
                                                        })()}
                                                    </td>
                                                    <td colSpan="2" className="px-4 py-2 text-xs text-stone-600">
                                                        └ 분리 #{splitIdx + 1} {split.memo && `- ${split.memo}`}
                                                    </td>
                                                    <td className="px-4 py-2 text-center">
                                                        <span className={`px-2 py-1 rounded text-xs font-bold ${
                                                            (split.deduction_type || split.deductionType) === 'non_deductible'
                                                                ? 'bg-red-500 text-white'
                                                                : 'bg-green-100 text-green-700'
                                                        }`}>
                                                            {(split.deduction_type || split.deductionType) === 'non_deductible' ? '불공' : '공제'}
                                                        </span>
                                                    </td>
                                                    <td></td>
                                                    <td></td>
                                                    <td className="px-4 py-2 text-xs text-stone-600">
                                                        {split.evidence_name || split.evidenceName || '-'}
                                                    </td>
                                                    <td className="px-4 py-2 text-xs text-stone-600">
                                                        {split.description || '-'}
                                                    </td>
                                                    <td className="px-4 py-2 text-right font-medium text-amber-700 text-sm">
                                                        {new Intl.NumberFormat('ko-KR').format(splitTotal)}원
                                                    </td>
                                                    <td className="px-4 py-2 text-right text-xs text-amber-600">
                                                        {new Intl.NumberFormat('ko-KR').format(splitSupply)}원
                                                    </td>
                                                    <td className="px-4 py-2 text-right text-xs text-amber-600">
                                                        {new Intl.NumberFormat('ko-KR').format(splitTax)}원
                                                    </td>
                                                    <td className="px-4 py-2 text-xs">
                                                        {split.account_code || split.accountCode ? (
                                                            <span className="text-purple-600">
                                                                {split.account_code || split.accountCode} {split.account_name || split.accountName}
                                                            </span>
                                                        ) : (
                                                            <span className="text-stone-400">미지정</span>
                                                        )}
                                                    </td>
                                                    <td></td>
                                                </tr>
                                                );
                                            })}
                                        </React.Fragment>
                                    );
                                })
                            )}
                        </tbody>
                    </table>
                </div>

                {/* 숨김 데이터 영역 */}
                {showHidden && (
                    <div className="border-t-2 border-red-200 bg-red-50/50">
                        <div className="p-4">
                            <div className="flex items-center gap-2 mb-3">
                                <svg className="w-5 h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L3 3m6.878 6.878L21 21" />
                                </svg>
                                <h3 className="text-sm font-bold text-red-700">숨김 처리된 거래 ({hiddenLogs.length}건)</h3>
                            </div>
                            {loadingHidden ? (
                                <div className="flex items-center justify-center py-6">
                                    <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-red-500"></div>
                                </div>
                            ) : hiddenLogs.length === 0 ? (
                                <p className="text-sm text-red-400 py-4 text-center">숨김 처리된 거래가 없습니다.</p>
                            ) : (
                                <table className="w-full text-left text-sm text-stone-600">
                                    <thead className="bg-red-100/50 text-xs uppercase font-medium text-red-500">
                                        <tr>
                                            <th className="px-4 py-2">사용일</th>
                                            <th className="px-4 py-2">카드번호</th>
                                            <th className="px-4 py-2">승인번호</th>
                                            <th className="px-4 py-2">가맹점명</th>
                                            <th className="px-4 py-2 text-right">금액</th>
                                            <th className="px-4 py-2">숨김일시</th>
                                            <th className="px-4 py-2 text-center">복원</th>
                                        </tr>
                                    </thead>
                                    <tbody className="divide-y divide-red-100">
                                        {hiddenLogs.map((h, i) => {
                                            const dateStr = h.useDate
                                                ? `${h.useDate.substring(0,4)}-${h.useDate.substring(4,6)}-${h.useDate.substring(6,8)}`
                                                : '-';
                                            return (
                                                <tr key={h.id || i} className="bg-red-50 hover:bg-red-100/50">
                                                    <td className="px-4 py-2 text-sm">{dateStr}</td>
                                                    <td className="px-4 py-2 text-sm font-mono">{h.cardNum}</td>
                                                    <td className="px-4 py-2 text-sm">{h.approvalNum || '-'}</td>
                                                    <td className="px-4 py-2 text-sm">{h.merchantName || '-'}</td>
                                                    <td className="px-4 py-2 text-sm text-right font-medium">{h.originalAmountFormatted}원</td>
                                                    <td className="px-4 py-2 text-xs text-stone-400">{h.hiddenAt}</td>
                                                    <td className="px-4 py-2 text-center">
                                                        <button
                                                            onClick={() => onRestore(h.uniqueKey)}
                                                            className="px-3 py-1 bg-green-500 text-white text-xs rounded-lg hover:bg-green-600 transition-colors font-medium"
                                                        >
                                                            복원
                                                        </button>
                                                    </td>
                                                </tr>
                                            );
                                        })}
                                    </tbody>
                                </table>
                            )}
                        </div>
                    </div>
                )}
            </div>
        );
    };

    // Main App Component
    const App = () => {
        const [loading, setLoading] = useState(true);
        const [saving, setSaving] = useState(false);
        const [cards, setCards] = useState([]);
        const [selectedCard, setSelectedCard] = useState('');
        const [logs, setLogs] = useState([]);
        const [summary, setSummary] = useState({});
        const [pagination, setPagination] = useState({});
        const [error, setError] = useState(null);
        const [accountCodes, setAccountCodes] = useState([]);
        const [hasChanges, setHasChanges] = useState(false);

        // 복식부기 분개 관련 상태
        const [journalMap, setJournalMap] = useState({});
        const [journalModalOpen, setJournalModalOpen] = useState(false);
        const [journalModalLog, setJournalModalLog] = useState(null);

        // 분리 관련 상태
        const [splits, setSplits] = useState({});
        const [splitModalOpen, setSplitModalOpen] = useState(false);
        const [splitModalLog, setSplitModalLog] = useState(null);
        const [splitModalKey, setSplitModalKey] = useState('');
        const [splitModalExisting, setSplitModalExisting] = useState([]);

        // 수동입력 관련 상태
        const [manualModalOpen, setManualModalOpen] = useState(false);
        const [manualEditData, setManualEditData] = useState(null);

        // 숨김 관련 상태
        const [showHidden, setShowHidden] = useState(false);
        const [hiddenLogs, setHiddenLogs] = useState([]);
        const [loadingHidden, setLoadingHidden] = useState(false);

        // 가맹점명 모달
        const [merchantNameModal, setMerchantNameModal] = useState(null);

        useEffect(() => {
            const handler = () => setMerchantNameModal(window._merchantModal || '');
            window.addEventListener('showMerchantModal', handler);
            return () => window.removeEventListener('showMerchantModal', handler);
        }, []);

        // 날짜 필터 상태 (기본: 현재 월)
        const currentMonth = getMonthDates(0);
        const [dateFrom, setDateFrom] = useState(currentMonth.from);
        const [dateTo, setDateTo] = useState(currentMonth.to);

        const isInitialMount = useRef(true);

        // 초기 로드
        useEffect(() => {
            loadCards();
            loadAccountCodes();
            loadTransactions();
        }, []);

        // 카드 선택 변경 시 자동 조회
        useEffect(() => {
            if (isInitialMount.current) {
                isInitialMount.current = false;
                return;
            }
            loadTransactions();
        }, [selectedCard]);

        const loadCards = async () => {
            try {
                const response = await fetch(API.cards);
                const data = await response.json();
                if (data.success) {
                    setCards(data.cards || []);
                }
            } catch (err) {
                console.error('카드 목록 로드 오류:', err);
            }
        };

        const loadAccountCodes = async () => {
            try {
                const response = await fetch(API.accountCodes);
                const data = await response.json();
                if (data.success) {
                    setAccountCodes(data.data || []);
                }
            } catch (err) {
                console.error('계정과목 목록 로드 오류:', err);
            }
        };

        const loadTransactions = async (page = 1) => {
            setLoading(true);
            setError(null);
            setHasChanges(false);

            try {
                const params = new URLSearchParams({
                    startDate: dateFrom.replace(/-/g, ''),
                    endDate: dateTo.replace(/-/g, ''),
                    cardNum: selectedCard,
                    page: page,
                    limit: 200
                });

                const response = await fetch(`${API.transactions}?${params}`);
                const data = await response.json();

                if (data.success) {
                    setLogs(data.data?.logs || []);
                    setPagination(data.data?.pagination || {});
                    setSummary(data.data?.summary || {});
                } else {
                    setError(data.error || '조회 실패');
                    setLogs([]);
                }
            } catch (err) {
                setError('서버 통신 오류: ' + err.message);
                setLogs([]);
            } finally {
                setLoading(false);
            }

            // 분리 데이터 로드
            loadSplits();
            loadJournalStatuses();
        };

        // 분리 데이터 로드
        const loadSplits = async () => {
            try {
                const params = new URLSearchParams({
                    startDate: dateFrom.replace(/-/g, ''),
                    endDate: dateTo.replace(/-/g, '')
                });
                const response = await fetch(`${API.splits}?${params}`);
                const data = await response.json();
                if (data.success) {
                    const newSplits = data.data || {};
                    setSplits(newSplits);
                    // useEffect에서 splits 변경 감지하여 재계산 처리
                }
            } catch (err) {
                console.error('분리 데이터 로드 오류:', err);
            }
        };

        // 복식부기 분개 상태 로드
        const loadJournalStatuses = async () => {
            try {
                const params = new URLSearchParams({
                    startDate: dateFrom.replace(/-/g, ''),
                    endDate: dateTo.replace(/-/g, '')
                });
                const response = await fetch(`${API.journalStatuses}?${params}`);
                const data = await response.json();
                if (data.success) {
                    setJournalMap(data.data || {});
                }
            } catch (err) {
                console.error('분개 상태 로드 오류:', err);
            }
        };

        // 복식부기 분개 모달 열기
        const handleOpenJournalModal = (log, sourceKey, hasJournal, logSplits, singleSplit) => {
            const logWithJournalInfo = {
                ...log,
                uniqueKey: sourceKey,
                _hasJournal: hasJournal,
                _journalData: null,
                _splits: logSplits || [],
                _split: singleSplit || null,
            };
            setJournalModalLog(logWithJournalInfo);
            setJournalModalOpen(true);
        };

        // 복식부기 분개 저장
        const handleSaveJournal = async (payload) => {
            try {
                const response = await fetch(API.journalStore, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN,
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify(payload)
                });

                const data = await response.json();
                if (data.success) {
                    notify(data.message, 'success');
                    setJournalModalOpen(false);
                    setJournalModalLog(null);
                    loadJournalStatuses();
                    loadSplits(); // splits 상태 갱신
                } else {
                    notify(data.message || '분개 저장 실패', 'error');
                }
            } catch (err) {
                notify('분개 저장 오류: ' + err.message, 'error');
            }
        };

        // 복식부기 분개 삭제
        const handleDeleteJournal = async (journalId) => {
            try {
                const response = await fetch(`${API.journalDelete}${journalId}`, {
                    method: 'DELETE',
                    headers: {
                        'X-CSRF-TOKEN': CSRF_TOKEN,
                        'Accept': 'application/json'
                    }
                });

                const data = await response.json();
                if (data.success) {
                    notify(data.message, 'success');
                    setJournalModalOpen(false);
                    setJournalModalLog(null);
                    loadJournalStatuses();
                } else {
                    notify(data.message || '분개 삭제 실패', 'error');
                }
            } catch (err) {
                notify('분개 삭제 오류: ' + err.message, 'error');
            }
        };

        // 요약 재계산: 분리가 있는 거래는 원본 대신 분리별 통계로 대체
        // 수정된 공급가액/세액이 있으면 해당 값으로 합계 반영
        const recalculateSummary = (currentLogs, allSplits) => {
            if (!currentLogs || currentLogs.length === 0) return;

            let totalAmount = 0;
            let deductibleAmount = 0;
            let deductibleCount = 0;
            let deductibleSupply = 0;
            let deductibleTax = 0;
            let nonDeductibleAmount = 0;
            let nonDeductibleCount = 0;
            let totalTax = 0;

            currentLogs.forEach(log => {
                const uniqueKey = log.uniqueKey || `${log.cardNum}|${log.useDt}|${log.approvalNum}|${Math.floor(log.approvalAmount)}`;
                const logSplits = allSplits[uniqueKey] || [];

                if (logSplits.length > 0) {
                    // 분리가 있는 거래: 각 분리별로 계산
                    logSplits.forEach(split => {
                        const splitSupply = split.split_supply_amount !== null && split.split_supply_amount !== undefined
                            ? parseFloat(split.split_supply_amount) : parseFloat(split.split_amount || 0);
                        const splitTax = split.split_tax !== null && split.split_tax !== undefined
                            ? parseFloat(split.split_tax) : 0;
                        const splitTotal = Math.abs(splitSupply + splitTax);
                        const splitType = split.deduction_type || split.deductionType || 'non_deductible';

                        totalAmount += splitTotal;
                        if (splitType === 'deductible') {
                            deductibleAmount += splitTotal;
                            deductibleCount++;
                            deductibleSupply += Math.abs(splitSupply);
                            deductibleTax += Math.abs(splitTax);
                            totalTax += Math.abs(splitTax);
                        } else {
                            nonDeductibleAmount += splitTotal;
                            nonDeductibleCount++;
                        }
                    });
                } else {
                    // 분리가 없는 거래: 수정된 금액(effectiveSupplyAmount/effectiveTax)으로 계산
                    const type = log.deductionType || 'non_deductible';
                    const effSupply = Math.abs(log.effectiveSupplyAmount ?? ((log.approvalAmount || 0) - (log.tax || 0)));
                    const effTax = Math.abs(log.effectiveTax ?? (log.tax || 0));
                    const amount = effSupply + effTax;

                    totalAmount += amount;
                    if (type === 'deductible') {
                        deductibleAmount += amount;
                        deductibleCount++;
                        deductibleSupply += effSupply;
                        deductibleTax += effTax;
                        totalTax += effTax;
                    } else {
                        nonDeductibleAmount += amount;
                        nonDeductibleCount++;
                    }
                }
            });

            setSummary(prev => ({
                ...prev,
                totalAmount,
                deductibleAmount,
                deductibleCount,
                deductibleSupply,
                deductibleTax,
                nonDeductibleAmount,
                nonDeductibleCount,
                totalTax,
            }));
        };

        // splits 또는 logs 변경 시 요약 재계산
        // 페이지네이션 중이면(전체 데이터가 아니면) 백엔드 통계를 유지
        useEffect(() => {
            if (logs.length > 0) {
                const totalCount = summary.count || 0;
                if (totalCount <= logs.length) {
                    // 전체 데이터가 한 페이지에 있으므로 분리 반영 재계산
                    recalculateSummary(logs, splits);
                }
                // 페이지네이션 중이면 백엔드 전체 통계 유지
            }
        }, [splits, logs]);

        // 분리 모달 열기
        const handleOpenSplitModal = (log, uniqueKey, existingSplits = []) => {
            setSplitModalLog(log);
            setSplitModalKey(uniqueKey);
            setSplitModalExisting(existingSplits);
            setSplitModalOpen(true);
        };

        // 분리 저장
        const handleSaveSplits = async (log, splitData) => {
            try {
                const uniqueKey = splitModalKey;
                const response = await fetch(API.saveSplits, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN,
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify({
                        uniqueKey: uniqueKey,
                        originalData: {
                            cardNum: log.cardNum,
                            useDt: log.useDt,
                            useDate: log.useDate,
                            approvalNum: log.approvalNum,
                            originalAmount: log.approvalAmount,
                            merchantName: log.merchantName
                        },
                        splits: splitData
                    })
                });

                const data = await response.json();
                if (data.success) {
                    notify(data.message, 'success');
                    loadSplits(); // 분리 데이터 새로고침
                } else {
                    notify(data.error || '분리 저장 실패', 'error');
                }
            } catch (err) {
                notify('분리 저장 오류: ' + err.message, 'error');
            }
        };

        // 분리 삭제
        const handleDeleteSplits = async (uniqueKey) => {
            if (!confirm('분리를 삭제하시겠습니까? 원본 거래로 복원됩니다.')) return;

            try {
                const response = await fetch(API.deleteSplits, {
                    method: 'DELETE',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN,
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify({ uniqueKey })
                });

                const data = await response.json();
                if (data.success) {
                    notify(data.message, 'success');
                    loadSplits(); // 분리 데이터 새로고침
                } else {
                    notify(data.error || '분리 삭제 실패', 'error');
                }
            } catch (err) {
                notify('분리 삭제 오류: ' + err.message, 'error');
            }
        };

        // 분리 복구 (모달에서 호출)
        const handleResetSplits = async (log) => {
            const uniqueKey = log.uniqueKey || `${log.cardNum}|${log.useDt}|${log.approvalNum}|${Math.floor(log.approvalAmount)}`;
            try {
                const response = await fetch(API.deleteSplits, {
                    method: 'DELETE',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN,
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify({ uniqueKey })
                });

                const data = await response.json();
                if (data.success) {
                    notify('분리가 복구되었습니다.', 'success');
                    loadSplits(); // 분리 데이터 새로고침
                } else {
                    notify(data.error || '분리 복구 실패', 'error');
                }
            } catch (err) {
                notify('분리 복구 오류: ' + err.message, 'error');
            }
        };

        // 수동입력 - 새로 등록 열기
        const handleManualNew = () => {
            setManualEditData(null);
            setManualModalOpen(true);
        };

        // 수동입력 - 수정 열기
        const handleManualEdit = (log) => {
            setManualEditData(log);
            setManualModalOpen(true);
        };

        // 수동입력 - 저장 (등록/수정)
        const handleManualSave = async (formData, editId) => {
            try {
                const isEdit = !!editId;
                const url = isEdit
                    ? API.manualUpdate.replace(':id', editId)
                    : API.manualStore;
                const method = isEdit ? 'PUT' : 'POST';

                const response = await fetch(url, {
                    method,
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN,
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify(formData)
                });

                const data = await response.json();
                if (data.success) {
                    notify(data.message, 'success');
                    setManualModalOpen(false);
                    setManualEditData(null);
                    loadTransactions();
                } else {
                    notify(data.error || '저장 실패', 'error');
                }
            } catch (err) {
                notify('저장 오류: ' + err.message, 'error');
            }
        };

        // 수동입력 - 삭제
        const handleManualDelete = async (id) => {
            if (!confirm('이 수동 입력 건을 삭제하시겠습니까?')) return;

            try {
                const url = API.manualDestroy.replace(':id', id);
                const response = await fetch(url, {
                    method: 'DELETE',
                    headers: {
                        'X-CSRF-TOKEN': CSRF_TOKEN,
                        'Accept': 'application/json'
                    }
                });

                const data = await response.json();
                if (data.success) {
                    notify(data.message, 'success');
                    loadTransactions();
                } else {
                    notify(data.error || '삭제 실패', 'error');
                }
            } catch (err) {
                notify('삭제 오류: ' + err.message, 'error');
            }
        };

        // 거래 숨김 처리
        const handleHide = async (log, uniqueKey) => {
            if (!confirm('이 거래를 숨기시겠습니까?\n(삭제데이터 보기에서 복원 가능)')) return;

            try {
                const response = await fetch(API.hide, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN,
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify({
                        uniqueKey,
                        originalData: {
                            cardNum: log.cardNum,
                            useDate: log.useDate,
                            approvalNum: log.approvalNum,
                            approvalAmount: log.approvalAmount,
                            merchantName: log.merchantName,
                        }
                    })
                });

                const data = await response.json();
                if (data.success) {
                    notify(data.message, 'success');
                    loadTransactions();
                    if (showHidden) loadHidden();
                } else {
                    notify(data.error || '숨김 처리 실패', 'error');
                }
            } catch (err) {
                notify('숨김 처리 오류: ' + err.message, 'error');
            }
        };

        // 거래 복원
        const handleRestore = async (uniqueKey) => {
            if (!confirm('이 거래를 복원하시겠습니까?')) return;

            try {
                const response = await fetch(API.restore, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN,
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify({ uniqueKey })
                });

                const data = await response.json();
                if (data.success) {
                    notify(data.message, 'success');
                    loadTransactions();
                    loadHidden();
                } else {
                    notify(data.error || '복원 실패', 'error');
                }
            } catch (err) {
                notify('복원 오류: ' + err.message, 'error');
            }
        };

        // 숨김 데이터 로드
        const loadHidden = async () => {
            setLoadingHidden(true);
            try {
                const params = new URLSearchParams({
                    startDate: dateFrom.replace(/-/g, ''),
                    endDate: dateTo.replace(/-/g, '')
                });
                const response = await fetch(`${API.hidden}?${params}`);
                const data = await response.json();
                if (data.success) {
                    setHiddenLogs(data.data || []);
                }
            } catch (err) {
                console.error('숨김 데이터 로드 오류:', err);
            } finally {
                setLoadingHidden(false);
            }
        };

        // 삭제데이터 보기 토글
        const handleToggleHidden = () => {
            const newVal = !showHidden;
            setShowHidden(newVal);
            if (newVal) {
                loadHidden();
            }
        };

        // 계정과목 변경 핸들러
        const handleAccountCodeChange = useCallback((index, code, name) => {
            setLogs(prevLogs => {
                const newLogs = [...prevLogs];
                newLogs[index] = {
                    ...newLogs[index],
                    accountCode: code,
                    accountName: name
                };
                return newLogs;
            });
            setHasChanges(true);
        }, []);

        // 필드 변경 핸들러 (공제, 증빙/판매자상호, 내역)
        const handleFieldChange = useCallback((index, field, value) => {
            setLogs(prevLogs => {
                const newLogs = [...prevLogs];
                newLogs[index] = {
                    ...newLogs[index],
                    [field]: value
                };
                return newLogs;
            });
            setHasChanges(true);
        }, []);

        // 저장 핸들러
        const handleSave = async () => {
            if (logs.length === 0) return;

            setSaving(true);
            try {
                const response = await fetch(API.save, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN,
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify({ transactions: logs })
                });

                const data = await response.json();
                if (data.success) {
                    notify(data.message, 'success');
                    setHasChanges(false);
                    // 저장 후 다시 로드하여 isSaved 상태 갱신
                    loadTransactions();
                } else {
                    notify(data.error || '저장 실패', 'error');
                }
            } catch (err) {
                notify('저장 오류: ' + err.message, 'error');
            } finally {
                setSaving(false);
            }
        };

        // 엑셀 다운로드 핸들러
        const handleExport = async () => {
            if (logs.length === 0) {
                notify('내보낼 데이터가 없습니다.', 'error');
                return;
            }

            try {
                const response = await fetch(API.export, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN,
                        'Accept': 'text/csv'
                    },
                    body: JSON.stringify({
                        startDate: dateFrom.replace(/-/g, ''),
                        endDate: dateTo.replace(/-/g, ''),
                        logs: logs,
                        splits: splits
                    })
                });

                if (!response.ok) {
                    const errorData = await response.json();
                    notify(errorData.error || '다운로드 실패', 'error');
                    return;
                }

                // Blob으로 파일 다운로드
                const blob = await response.blob();
                const url = window.URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = `카드사용내역_${dateFrom.replace(/-/g, '')}_${dateTo.replace(/-/g, '')}.csv`;
                document.body.appendChild(a);
                a.click();
                window.URL.revokeObjectURL(url);
                a.remove();
                notify('엑셀 다운로드 완료', 'success');
            } catch (err) {
                notify('다운로드 오류: ' + err.message, 'error');
            }
        };

        // 이번 달 버튼
        const handleThisMonth = () => {
            const dates = getMonthDates(0);
            setDateFrom(dates.from);
            setDateTo(dates.to);
        };

        // 지난달 버튼
        const handleLastMonth = () => {
            const dates = getMonthDates(-1);
            setDateFrom(dates.from);
            setDateTo(dates.to);
        };

        // N개월 전 버튼 (offset: -2, -3, -4 등)
        const handleMonthOffset = (offset) => {
            const dates = getMonthDates(offset);
            setDateFrom(dates.from);
            setDateTo(dates.to);
        };

        const formatCurrency = (val) => new Intl.NumberFormat('ko-KR').format(val || 0) + '원';

        return (
            <div className="space-y-6">
                {/* Page Header - 계좌입출금 스타일 */}
                <div className="flex items-center justify-between">
                    <div className="flex items-center gap-4">
                        <div className="p-2.5 bg-purple-100 rounded-xl">
                            <svg className="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />
                            </svg>
                        </div>
                        <div>
                            <h1 className="text-2xl font-bold text-stone-900">카드 사용내역</h1>
                            <p className="text-stone-500 mt-1">바로빌 API를 통한 카드 사용내역 조회 및 계정과목 관리</p>
                        </div>
                    </div>
                    <div className="flex items-center gap-2">
                        @if($isTestMode)
                        <span className="px-3 py-1 bg-amber-100 text-amber-700 rounded-full text-xs font-medium">테스트 모드</span>
                        @else
                        <span className="px-3 py-1 bg-red-100 text-red-700 rounded-full text-xs font-medium flex items-center gap-1">
                            <svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
                                <path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd"/>
                            </svg>
                            운영 모드
                        </span>
                        @endif
                        @if($hasSoapClient)
                        <span className="px-3 py-1 bg-green-100 text-green-700 rounded-full text-xs font-medium">SOAP 연결됨</span>
                        @else
                        <span className="px-3 py-1 bg-red-100 text-red-700 rounded-full text-xs font-medium">SOAP 미연결</span>
                        @endif
                    </div>
                </div>

                {/* 통계 + 카드 선택 (한 줄) - 계좌입출금 스타일 */}
                <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-4">
                    <div className="flex flex-wrap items-center gap-3">
                        <CompactStat label="사용액" value={formatCurrency(summary.totalAmount)} color="purple" />
                        <CompactStat label="공제" value={formatCurrency(summary.deductibleAmount)} color="green" />
                        <CompactStat label="불공제" value={formatCurrency(summary.nonDeductibleAmount)} color="red" />
                        <CompactStat label="카드" value={`${cards.length}개`} color="stone" />
                        <CompactStat label="거래" value={`${(summary.count || logs.length).toLocaleString()}건`} color="stone" />

                        {/* 구분선 */}
                        {cards.length > 0 && <div className="w-px h-6 bg-stone-200 mx-1"></div>}

                        {/* 카드 선택 드롭다운 */}
                        {cards.length > 0 && (
                            <>
                                <span className="text-xs text-stone-500">카드:</span>
                                <select
                                    value={selectedCard}
                                    onChange={(e) => setSelectedCard(e.target.value)}
                                    className="px-3 py-2 text-sm border border-gray-200 rounded-lg bg-white text-stone-700 focus:ring-2 focus:ring-purple-500 outline-none"
                                >
                                    <option value="">전체 카드</option>
                                    {cards.map(card => (
                                        <option key={card.cardNum} value={card.cardNum}>
                                            {card.cardBrand} ****{card.cardNum ? card.cardNum.slice(-4) : ''}
                                        </option>
                                    ))}
                                </select>
                            </>
                        )}
                    </div>
                </div>

                {/* 필터 영역 - 날짜/조회/액션 버튼 통합 */}
                <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-4">
                    <div className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4">
                        {/* 기간 조회 필터 */}
                        <div className="flex flex-wrap items-center gap-3">
                            <div className="flex items-center gap-2">
                                <label className="text-sm text-stone-500">기간</label>
                                <input
                                    type="date"
                                    value={dateFrom}
                                    onChange={(e) => setDateFrom(e.target.value)}
                                    className="rounded-lg border border-gray-200 px-3 py-1.5 text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                />
                                <span className="text-stone-400">~</span>
                                <input
                                    type="date"
                                    value={dateTo}
                                    onChange={(e) => setDateTo(e.target.value)}
                                    className="rounded-lg border border-gray-200 px-3 py-1.5 text-sm focus:ring-2 focus:ring-purple-500 outline-none"
                                />
                            </div>
                            <div className="flex items-center gap-2">
                                <button
                                    onClick={handleThisMonth}
                                    className="px-3 py-1.5 text-sm bg-purple-50 text-purple-600 rounded-lg hover:bg-purple-100 transition-colors font-medium"
                                >
                                    이번 달
                                </button>
                                <button
                                    onClick={handleLastMonth}
                                    className="px-3 py-1.5 text-sm bg-stone-100 text-stone-600 rounded-lg hover:bg-stone-200 transition-colors font-medium"
                                >
                                    지난달
                                </button>
                                <button
                                    onClick={() => handleMonthOffset(-2)}
                                    className="px-3 py-1.5 text-sm bg-stone-100 text-stone-600 rounded-lg hover:bg-stone-200 transition-colors font-medium"
                                >
                                    D-2월
                                </button>
                                <button
                                    onClick={() => handleMonthOffset(-3)}
                                    className="px-3 py-1.5 text-sm bg-stone-100 text-stone-600 rounded-lg hover:bg-stone-200 transition-colors font-medium"
                                >
                                    D-3월
                                </button>
                                <button
                                    onClick={() => handleMonthOffset(-4)}
                                    className="px-3 py-1.5 text-sm bg-stone-100 text-stone-600 rounded-lg hover:bg-stone-200 transition-colors font-medium"
                                >
                                    D-4월
                                </button>
                                <button
                                    onClick={() => handleMonthOffset(-5)}
                                    className="px-3 py-1.5 text-sm bg-stone-100 text-stone-600 rounded-lg hover:bg-stone-200 transition-colors font-medium"
                                >
                                    D-5월
                                </button>
                                <button
                                    onClick={() => loadTransactions()}
                                    className="px-4 py-1.5 text-sm bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors font-medium flex items-center gap-2"
                                >
                                    <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
                                    </svg>
                                    조회
                                </button>
                            </div>
                            <span className="text-sm text-stone-500 ml-2">
                                조회: <span className="font-semibold text-stone-700">{logs.length}</span>건
                                {(summary.count || logs.length) !== logs.length && (
                                    <span className="text-stone-400"> / 전체 {summary.count}건</span>
                                )}
                            </span>
                        </div>
                        {/* 액션 버튼들 */}
                        <div className="flex items-center gap-2">
                            <button
                                onClick={handleSave}
                                disabled={saving || logs.length === 0}
                                className={`flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
                                    hasChanges
                                        ? 'bg-purple-600 text-white hover:bg-purple-700'
                                        : 'bg-purple-100 text-purple-700 hover:bg-purple-200'
                                } disabled:opacity-50 disabled:cursor-not-allowed`}
                            >
                                {saving ? (
                                    <svg className="animate-spin w-4 h-4" fill="none" viewBox="0 0 24 24">
                                        <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
                                        <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path>
                                    </svg>
                                ) : (
                                    <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4" />
                                    </svg>
                                )}
                                {hasChanges ? '변경사항 저장' : '저장'}
                            </button>
                            <button
                                onClick={handleManualNew}
                                className="flex items-center gap-2 px-4 py-2 bg-green-100 text-green-700 rounded-lg text-sm font-medium hover:bg-green-200 transition-colors"
                            >
                                <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 4v16m8-8H4" />
                                </svg>
                                수동입력
                            </button>
                            <button
                                onClick={handleExport}
                                disabled={logs.length === 0}
                                className="flex items-center gap-2 px-4 py-2 bg-blue-100 text-blue-700 rounded-lg text-sm font-medium hover:bg-blue-200 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                            >
                                <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
                                </svg>
                                엑셀
                            </button>
                            <button
                                onClick={handleToggleHidden}
                                className={`flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
                                    showHidden
                                        ? 'bg-red-600 text-white hover:bg-red-700'
                                        : 'bg-red-100 text-red-700 hover:bg-red-200'
                                }`}
                            >
                                <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.878 9.878L3 3m6.878 6.878L21 21" />
                                </svg>
                                {showHidden ? '삭제데이터 닫기' : '삭제데이터'}
                                {showHidden && hiddenLogs.length > 0 && (
                                    <span className="bg-white text-red-600 text-xs px-1.5 py-0.5 rounded-full font-bold">{hiddenLogs.length}</span>
                                )}
                            </button>
                        </div>
                    </div>
                </div>

                {/* Error Display */}
                {error && (
                    <div className="bg-red-50 border border-red-200 text-red-600 p-4 rounded-xl">
                        <div className="flex items-start gap-3">
                            <div className="text-xl">⚠️</div>
                            <div className="flex-1">
                                <p className="font-semibold mb-2">{error}</p>
                                {error.includes('-25') && (
                                    <div className="mt-3 p-3 bg-white rounded border border-red-200 text-sm">
                                        <p className="font-medium mb-2">해결 방법:</p>
                                        <ol className="list-decimal list-inside space-y-1 text-stone-700">
                                            <li>바로빌 사이트(<a href="https://www.barobill.co.kr" target="_blank" className="text-blue-600 hover:underline">https://www.barobill.co.kr</a>)에 로그인</li>
                                            <li>카드 관리 메뉴에서 해당 카드 확인</li>
                                            <li>카드 인증 정보가 만료되지 않았는지 확인</li>
                                            <li>필요시 카드 재등록</li>
                                        </ol>
                                    </div>
                                )}
                            </div>
                        </div>
                    </div>
                )}

                {/* Transaction Table */}
                {!error && (
                    <TransactionTable
                        logs={logs}
                        loading={loading}
                        totalCount={summary.count || logs.length}
                        accountCodes={accountCodes}
                        onAccountCodeChange={handleAccountCodeChange}
                        onFieldChange={handleFieldChange}
                        splits={splits}
                        onOpenSplitModal={handleOpenSplitModal}
                        onDeleteSplits={handleDeleteSplits}
                        onManualEdit={handleManualEdit}
                        onManualDelete={handleManualDelete}
                        onHide={handleHide}
                        showHidden={showHidden}
                        hiddenLogs={hiddenLogs}
                        onRestore={handleRestore}
                        loadingHidden={loadingHidden}
                        journalMap={journalMap}
                        onOpenJournalModal={handleOpenJournalModal}
                    />
                )}

                {/* Split Modal */}
                <SplitModal
                    isOpen={splitModalOpen}
                    onClose={() => setSplitModalOpen(false)}
                    log={splitModalLog}
                    accountCodes={accountCodes}
                    onSave={handleSaveSplits}
                    onReset={handleResetSplits}
                    splits={splitModalExisting}
                />

                {/* Card Journal Modal (복식부기) */}
                <CardJournalModal
                    isOpen={journalModalOpen}
                    onClose={() => { setJournalModalOpen(false); setJournalModalLog(null); }}
                    onSave={handleSaveJournal}
                    onDelete={handleDeleteJournal}
                    log={journalModalLog}
                    accountCodes={accountCodes}
                />

                {/* Manual Entry Modal */}
                <ManualEntryModal
                    isOpen={manualModalOpen}
                    onClose={() => { setManualModalOpen(false); setManualEditData(null); }}
                    onSave={handleManualSave}
                    editData={manualEditData}
                    accountCodes={accountCodes}
                    cards={cards}
                />

                {/* Merchant Name Modal */}
                {merchantNameModal !== null && (
                    <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50" onClick={() => setMerchantNameModal(null)}>
                        <div className="bg-white rounded-xl shadow-xl p-6 max-w-md w-full mx-4" onClick={(e) => e.stopPropagation()}>
                            <div className="flex items-center justify-between mb-4">
                                <h3 className="text-sm font-bold text-stone-900">가맹점명</h3>
                                <button onClick={() => setMerchantNameModal(null)} className="text-stone-400 hover:text-stone-600">
                                    <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
                                    </svg>
                                </button>
                            </div>
                            <p className="text-stone-800 break-all">{merchantNameModal}</p>
                        </div>
                    </div>
                )}

                {/* Pagination */}
                {!error && pagination.maxPageNum > 1 && (
                    <div className="flex justify-center gap-2">
                        <button
                            onClick={() => loadTransactions(Math.max(1, pagination.currentPage - 1))}
                            disabled={pagination.currentPage === 1}
                            className="px-3 py-1 rounded bg-white border disabled:opacity-50"
                        >
                            이전
                        </button>
                        <span className="px-3 py-1">
                            {pagination.currentPage} / {pagination.maxPageNum}
                        </span>
                        <button
                            onClick={() => loadTransactions(Math.min(pagination.maxPageNum, pagination.currentPage + 1))}
                            disabled={pagination.currentPage === pagination.maxPageNum}
                            className="px-3 py-1 rounded bg-white border disabled:opacity-50"
                        >
                            다음
                        </button>
                    </div>
                )}
            </div>
        );
    };

    const root = ReactDOM.createRoot(document.getElementById('ecard-root'));
    root.render(<App />);
</script>
@endpush
