@extends('layouts.app')

@section('title', '계좌 입출금내역')

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

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

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

    // API Routes
    const API = {
        accounts: '{{ route("barobill.eaccount.accounts") }}',
        transactions: '{{ route("barobill.eaccount.transactions") }}',
        accountCodes: '{{ route("barobill.eaccount.account-codes") }}',
        accountCodesAll: '{{ route("barobill.eaccount.account-codes.all") }}',
        accountCodesStore: '{{ route("barobill.eaccount.account-codes.store") }}',
        accountCodesUpdate: (id) => `/barobill/eaccount/account-codes/${id}`,
        accountCodesDestroy: (id) => `/barobill/eaccount/account-codes/${id}`,
        save: '{{ route("barobill.eaccount.save") }}',
        export: '{{ route("barobill.eaccount.export") }}',
        saveOverride: '{{ route("barobill.eaccount.save-override") }}',
        manualStore: '{{ route("barobill.eaccount.manual.store") }}',
        manualUpdate: '{{ route("barobill.eaccount.manual.update", ":id") }}',
        manualDestroy: '{{ route("barobill.eaccount.manual.destroy", ":id") }}',
        splits: '{{ route("barobill.eaccount.splits") }}',
        saveSplits: '{{ route("barobill.eaccount.splits.save") }}',
        deleteSplits: '{{ route("barobill.eaccount.splits.delete") }}',
        clientsSearch: '{{ route("barobill.eaccount.clients.search") }}',
    };

    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 year = now.getFullYear();
        const month = now.getMonth() + offset;
        const firstDay = new Date(year, month, 1);
        const lastDay = new Date(year, month + 1, 0);
        return {
            from: formatLocalDate(firstDay),
            to: formatLocalDate(lastDay)
        };
    };

    // 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 = {
            blue: 'text-blue-600',
            green: 'text-green-600',
            emerald: 'text-emerald-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-stone-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>
        );
    };

    // AccountSelector Component (컴팩트 버전)
    const AccountSelector = ({ accounts, selectedAccount, onSelect }) => (
        <div className="flex flex-wrap gap-1.5">
            <button
                onClick={() => onSelect('')}
                className={`px-2.5 py-1 rounded text-xs font-medium transition-colors ${
                    selectedAccount === ''
                        ? 'bg-emerald-600 text-white'
                        : 'bg-stone-100 text-stone-600 hover:bg-stone-200'
                }`}
            >
                전체
            </button>
            {accounts.map(acc => (
                <button
                    key={acc.bankAccountNum}
                    onClick={() => onSelect(acc.bankAccountNum)}
                    className={`px-2.5 py-1 rounded text-xs font-medium transition-colors ${
                        selectedAccount === acc.bankAccountNum
                            ? 'bg-emerald-600 text-white'
                            : 'bg-stone-100 text-stone-600 hover:bg-stone-200'
                    }`}
                >
                    {acc.bankName} ****{acc.bankAccountNum ? acc.bankAccountNum.slice(-4) : ''}
                </button>
            ))}
        </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-emerald-500 ring-2 ring-emerald-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-50 mt-1 w-48 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 py-1 text-xs border border-stone-200 rounded focus:ring-1 focus:ring-emerald-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-emerald-600 text-white font-semibold'
                                                : value === code.code
                                                    ? 'bg-emerald-100 text-emerald-700'
                                                    : 'text-stone-700 hover:bg-emerald-50'
                                        }`}
                                    >
                                        <span className={`font-mono ${index === highlightIndex ? 'text-white' : 'text-emerald-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>
        );
    };

    // ClientCodeSelect Component (서버 검색 기반 드롭다운)
    const ClientCodeSelect = ({ value, clientName, onChange }) => {
        const [isOpen, setIsOpen] = useState(false);
        const [search, setSearch] = useState('');
        const [highlightIndex, setHighlightIndex] = useState(-1);
        const [results, setResults] = useState([]);
        const [searching, setSearching] = useState(false);
        const containerRef = useRef(null);
        const listRef = useRef(null);
        const debounceRef = useRef(null);

        // 표시 텍스트
        const displayText = value ? `${value} ${clientName || ''}` : '';

        // 검색어 변경 시 debounce API 호출
        useEffect(() => {
            if (!isOpen) return;
            if (debounceRef.current) clearTimeout(debounceRef.current);

            if (!search || search.length < 1) {
                setResults([]);
                setHighlightIndex(-1);
                return;
            }

            setSearching(true);
            debounceRef.current = setTimeout(async () => {
                try {
                    const res = await fetch(`${API.clientsSearch}?q=${encodeURIComponent(search)}`);
                    const data = await res.json();
                    if (data.success) {
                        setResults(data.data || []);
                    }
                } catch (err) {
                    console.error('거래처 검색 오류:', err);
                } finally {
                    setSearching(false);
                    setHighlightIndex(-1);
                }
            }, 300);

            return () => {
                if (debounceRef.current) clearTimeout(debounceRef.current);
            };
        }, [search, isOpen]);

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

        const handleSelect = (item) => {
            onChange(item.code, item.name);
            setIsOpen(false);
            setSearch('');
            setHighlightIndex(-1);
            setResults([]);
        };

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

        // 키보드 네비게이션
        const handleKeyDown = (e) => {
            const maxIndex = results.length - 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' && results.length > 0) {
                e.preventDefault();
                const selectIndex = highlightIndex >= 0 ? highlightIndex : 0;
                handleSelect(results[selectIndex]);
            } else if (e.key === 'Escape') {
                setIsOpen(false);
                setSearch('');
                setHighlightIndex(-1);
                setResults([]);
            }
        };

        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-blue-500 ring-2 ring-blue-500' : 'border-stone-200'
                    } bg-white`}
                >
                    <span className={displayText ? 'text-stone-900 truncate' : 'text-stone-400'}>
                        {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 && (
                    <div className="absolute z-50 mt-1 w-56 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 py-1 text-xs border border-stone-200 rounded focus:ring-1 focus:ring-blue-500 outline-none"
                                autoFocus
                            />
                        </div>
                        {/* 옵션 목록 */}
                        <div ref={listRef} className="max-h-48 overflow-y-auto">
                            {searching ? (
                                <div className="px-3 py-2 text-xs text-stone-400 text-center">
                                    검색 중...
                                </div>
                            ) : results.length === 0 ? (
                                <div className="px-3 py-2 text-xs text-stone-400 text-center">
                                    {search ? '검색 결과 없음' : '검색어를 입력하세요'}
                                </div>
                            ) : (
                                results.map((item, index) => (
                                    <div
                                        key={item.code}
                                        onClick={() => handleSelect(item)}
                                        className={`px-3 py-1.5 text-xs cursor-pointer ${
                                            index === highlightIndex
                                                ? 'bg-blue-600 text-white font-semibold'
                                                : value === item.code
                                                    ? 'bg-blue-100 text-blue-700'
                                                    : 'text-stone-700 hover:bg-blue-50'
                                        }`}
                                    >
                                        <span className={`font-mono ${index === highlightIndex ? 'text-white' : 'text-blue-600'}`}>{item.code}</span>
                                        <span className="ml-1">{item.name}</span>
                                    </div>
                                ))
                            )}
                        </div>
                    </div>
                )}
            </div>
        );
    };

    // AccountCodeSettingsModal Component
    const AccountCodeSettingsModal = ({ isOpen, onClose, onUpdate }) => {
        const [codes, setCodes] = useState([]);
        const [loading, setLoading] = useState(false);
        const [newCode, setNewCode] = useState('');
        const [newName, setNewName] = useState('');
        const [newCategory, setNewCategory] = useState('');
        const [filter, setFilter] = useState('');
        const [categoryFilter, setCategoryFilter] = useState('');

        const categories = ['자산', '부채', '자본', '수익', '비용'];

        // 모달 열릴 때 데이터 로드
        useEffect(() => {
            if (isOpen) {
                loadCodes();
            }
        }, [isOpen]);

        const loadCodes = async () => {
            setLoading(true);
            try {
                const res = await fetch(API.accountCodesAll);
                const data = await res.json();
                if (data.success) {
                    setCodes(data.data || []);
                }
            } catch (err) {
                notify('계정과목 로드 실패', 'error');
            } finally {
                setLoading(false);
            }
        };

        const handleAdd = async () => {
            if (!newCode.trim() || !newName.trim()) {
                notify('코드와 이름을 입력해주세요.', 'warning');
                return;
            }

            try {
                const res = await fetch(API.accountCodesStore, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN
                    },
                    body: JSON.stringify({
                        code: newCode.trim(),
                        name: newName.trim(),
                        category: newCategory || null
                    })
                });
                const data = await res.json();
                if (data.success) {
                    notify('계정과목이 추가되었습니다.', 'success');
                    setNewCode('');
                    setNewName('');
                    setNewCategory('');
                    loadCodes();
                    onUpdate();
                } else {
                    notify(data.error || '추가 실패', 'error');
                }
            } catch (err) {
                notify('추가 실패: ' + err.message, 'error');
            }
        };

        const handleToggleActive = async (item) => {
            try {
                const res = await fetch(API.accountCodesUpdate(item.id), {
                    method: 'PUT',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN
                    },
                    body: JSON.stringify({ is_active: !item.is_active })
                });
                const data = await res.json();
                if (data.success) {
                    loadCodes();
                    onUpdate();
                }
            } catch (err) {
                notify('변경 실패', 'error');
            }
        };

        const handleDelete = async (item) => {
            if (!confirm(`"${item.code} ${item.name}" 계정과목을 삭제하시겠습니까?`)) return;

            try {
                const res = await fetch(API.accountCodesDestroy(item.id), {
                    method: 'DELETE',
                    headers: {
                        'X-CSRF-TOKEN': CSRF_TOKEN
                    }
                });
                const data = await res.json();
                if (data.success) {
                    notify('삭제되었습니다.', 'success');
                    loadCodes();
                    onUpdate();
                } else {
                    notify(data.error || '삭제 실패', 'error');
                }
            } catch (err) {
                notify('삭제 실패: ' + err.message, 'error');
            }
        };

        const filteredCodes = codes.filter(c => {
            const matchText = filter === '' ||
                c.code.includes(filter) ||
                c.name.includes(filter);
            const matchCategory = categoryFilter === '' || c.category === categoryFilter;
            return matchText && matchCategory;
        });

        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-xl shadow-2xl w-full max-w-4xl max-h-[90vh] overflow-hidden">
                    {/* Header */}
                    <div className="flex items-center justify-between px-6 py-4 border-b border-stone-200 bg-stone-50">
                        <h2 className="text-lg font-bold text-stone-900">계정과목 설정</h2>
                        <button onClick={onClose} className="text-stone-400 hover:text-stone-600 text-2xl">&times;</button>
                    </div>

                    {/* Add Form */}
                    <div className="px-6 py-4 border-b border-stone-100 bg-emerald-50/50">
                        <div className="flex gap-2 items-end">
                            <div className="flex-1">
                                <label className="block text-xs font-medium text-stone-600 mb-1">코드</label>
                                <input
                                    type="text"
                                    value={newCode}
                                    onChange={(e) => setNewCode(e.target.value)}
                                    placeholder="예: 101"
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                                />
                            </div>
                            <div className="flex-[2]">
                                <label className="block text-xs font-medium text-stone-600 mb-1">계정과목명</label>
                                <input
                                    type="text"
                                    value={newName}
                                    onChange={(e) => setNewName(e.target.value)}
                                    placeholder="예: 현금"
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                                />
                            </div>
                            <div className="flex-1">
                                <label className="block text-xs font-medium text-stone-600 mb-1">분류</label>
                                <select
                                    value={newCategory}
                                    onChange={(e) => setNewCategory(e.target.value)}
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                                >
                                    <option value="">선택</option>
                                    {categories.map(cat => (
                                        <option key={cat} value={cat}>{cat}</option>
                                    ))}
                                </select>
                            </div>
                            <button
                                onClick={handleAdd}
                                className="px-4 py-2 bg-emerald-600 text-white rounded-lg hover:bg-emerald-700 text-sm font-medium"
                            >
                                추가
                            </button>
                        </div>
                    </div>

                    {/* Filter */}
                    <div className="px-6 py-3 border-b border-stone-100 flex gap-3">
                        <input
                            type="text"
                            value={filter}
                            onChange={(e) => setFilter(e.target.value)}
                            placeholder="코드 또는 이름 검색..."
                            className="flex-1 px-3 py-2 border border-stone-200 rounded-lg text-sm"
                        />
                        <select
                            value={categoryFilter}
                            onChange={(e) => setCategoryFilter(e.target.value)}
                            className="px-3 py-2 border border-stone-200 rounded-lg text-sm"
                        >
                            <option value="">전체 분류</option>
                            {categories.map(cat => (
                                <option key={cat} value={cat}>{cat}</option>
                            ))}
                        </select>
                        <span className="text-sm text-stone-500 py-2">
                            {filteredCodes.length}개
                        </span>
                    </div>

                    {/* List */}
                    <div className="overflow-y-auto" style={ {maxHeight: '400px'} }>
                        {loading ? (
                            <div className="p-8 text-center text-stone-400">로딩 중...</div>
                        ) : (
                            <table className="w-full text-sm">
                                <thead className="bg-stone-50 sticky top-0">
                                    <tr>
                                        <th className="px-4 py-3 text-left font-medium text-stone-600">코드</th>
                                        <th className="px-4 py-3 text-left font-medium text-stone-600">계정과목명</th>
                                        <th className="px-4 py-3 text-left font-medium text-stone-600">분류</th>
                                        <th className="px-4 py-3 text-center font-medium text-stone-600">상태</th>
                                        <th className="px-4 py-3 text-center font-medium text-stone-600">작업</th>
                                    </tr>
                                </thead>
                                <tbody className="divide-y divide-stone-100">
                                    {filteredCodes.map(item => (
                                        <tr key={item.id} className={`hover:bg-stone-50 ${!item.is_active ? 'opacity-50' : ''}`}>
                                            <td className="px-4 py-2 font-mono">{item.code}</td>
                                            <td className="px-4 py-2">{item.name}</td>
                                            <td className="px-4 py-2">
                                                <span className={`px-2 py-0.5 rounded-full text-xs ${
                                                    item.category === '자산' ? 'bg-blue-100 text-blue-700' :
                                                    item.category === '부채' ? 'bg-red-100 text-red-700' :
                                                    item.category === '자본' ? 'bg-purple-100 text-purple-700' :
                                                    item.category === '수익' ? 'bg-green-100 text-green-700' :
                                                    item.category === '비용' ? 'bg-orange-100 text-orange-700' :
                                                    'bg-stone-100 text-stone-600'
                                                }`}>
                                                    {item.category || '-'}
                                                </span>
                                            </td>
                                            <td className="px-4 py-2 text-center">
                                                <button
                                                    onClick={() => handleToggleActive(item)}
                                                    className={`px-2 py-1 rounded text-xs ${
                                                        item.is_active
                                                            ? 'bg-green-100 text-green-700 hover:bg-green-200'
                                                            : 'bg-stone-100 text-stone-500 hover:bg-stone-200'
                                                    }`}
                                                >
                                                    {item.is_active ? '사용중' : '미사용'}
                                                </button>
                                            </td>
                                            <td className="px-4 py-2 text-center">
                                                <button
                                                    onClick={() => handleDelete(item)}
                                                    className="text-red-500 hover:text-red-700 text-xs"
                                                >
                                                    삭제
                                                </button>
                                            </td>
                                        </tr>
                                    ))}
                                </tbody>
                            </table>
                        )}
                    </div>

                    {/* Footer */}
                    <div className="px-6 py-4 border-t border-stone-200 bg-stone-50 flex justify-end">
                        <button
                            onClick={onClose}
                            className="px-6 py-2 bg-stone-600 text-white rounded-lg hover:bg-stone-700 font-medium"
                        >
                            닫기
                        </button>
                    </div>
                </div>
            </div>
        );
    };

    // 적요/내용 수정 모달 컴포넌트
    const TransactionEditModal = ({ isOpen, onClose, log, onSave }) => {
        const [modifiedSummary, setModifiedSummary] = useState('');
        const [modifiedCast, setModifiedCast] = useState('');
        const [saving, setSaving] = useState(false);

        useEffect(() => {
            if (isOpen && log) {
                // 현재 표시되는 값으로 초기화 (수정된 값이 있으면 그 값, 없으면 원본)
                setModifiedSummary(log.summary || '');
                setModifiedCast(log.cast || '');
            }
        }, [isOpen, log]);

        const handleSave = async () => {
            if (!log?.uniqueKey) {
                notify('고유 키가 없습니다.', 'error');
                return;
            }

            setSaving(true);
            try {
                const res = await fetch(API.saveOverride, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN,
                    },
                    body: JSON.stringify({
                        uniqueKey: log.uniqueKey,
                        modifiedSummary: modifiedSummary !== log.originalSummary ? modifiedSummary : null,
                        modifiedCast: modifiedCast !== log.originalCast ? modifiedCast : null,
                    }),
                });

                const data = await res.json();
                if (data.success) {
                    notify(data.message, 'success');
                    onSave(modifiedSummary, modifiedCast);
                    onClose();
                } else {
                    notify(data.error || '저장 실패', 'error');
                }
            } catch (err) {
                notify('저장 오류: ' + err.message, 'error');
            } finally {
                setSaving(false);
            }
        };

        const handleReset = async () => {
            if (!confirm('원본 값으로 되돌리시겠습니까?')) return;

            setSaving(true);
            try {
                const res = await fetch(API.saveOverride, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN,
                    },
                    body: JSON.stringify({
                        uniqueKey: log.uniqueKey,
                        modifiedSummary: null,
                        modifiedCast: null,
                    }),
                });

                const data = await res.json();
                if (data.success) {
                    notify('원본으로 복원되었습니다.', 'success');
                    onSave(log.originalSummary, log.originalCast);
                    onClose();
                } else {
                    notify(data.error || '복원 실패', 'error');
                }
            } catch (err) {
                notify('복원 오류: ' + err.message, 'error');
            } finally {
                setSaving(false);
            }
        };

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

        return (
            <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
                <div className="bg-white rounded-xl shadow-2xl w-full max-w-lg overflow-hidden">
                    {/* Header */}
                    <div className="flex items-center justify-between px-6 py-4 border-b border-stone-200 bg-stone-50">
                        <h2 className="text-lg font-bold text-stone-900">적요/내용 수정</h2>
                        <button onClick={onClose} className="text-stone-400 hover:text-stone-600 text-2xl">&times;</button>
                    </div>

                    {/* 거래 정보 */}
                    <div className="px-6 py-4 bg-emerald-50/50 border-b border-stone-100">
                        <div className="grid grid-cols-2 gap-4 text-sm">
                            <div>
                                <span className="text-stone-500">거래일시:</span>
                                <span className="ml-2 font-medium">{log.transDateTime}</span>
                            </div>
                            <div>
                                <span className="text-stone-500">계좌:</span>
                                <span className="ml-2 font-medium">{log.bankName}</span>
                            </div>
                            <div>
                                <span className="text-stone-500">입금:</span>
                                <span className="ml-2 font-medium text-blue-600">{log.deposit > 0 ? log.depositFormatted + '원' : '-'}</span>
                            </div>
                            <div>
                                <span className="text-stone-500">출금:</span>
                                <span className="ml-2 font-medium text-red-600">{log.withdraw > 0 ? log.withdrawFormatted + '원' : '-'}</span>
                            </div>
                        </div>
                    </div>

                    {/* 수정 폼 */}
                    <div className="px-6 py-4 space-y-4">
                        <div>
                            <label className="block text-sm font-medium text-stone-700 mb-1">
                                적요
                                {log.isOverridden && log.originalSummary !== modifiedSummary && (
                                    <span className="ml-2 text-xs text-amber-600">(수정됨)</span>
                                )}
                            </label>
                            <input
                                type="text"
                                value={modifiedSummary}
                                onChange={(e) => setModifiedSummary(e.target.value)}
                                className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                                placeholder="적요 입력"
                            />
                            {log.originalSummary && modifiedSummary !== log.originalSummary && (
                                <p className="mt-1 text-xs text-stone-400">원본: {log.originalSummary}</p>
                            )}
                        </div>

                        <div>
                            <label className="block text-sm font-medium text-stone-700 mb-1">
                                내용 (상대계좌예금주명)
                                {log.isOverridden && log.originalCast !== modifiedCast && (
                                    <span className="ml-2 text-xs text-amber-600">(수정됨)</span>
                                )}
                            </label>
                            <input
                                type="text"
                                value={modifiedCast}
                                onChange={(e) => setModifiedCast(e.target.value)}
                                className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                                placeholder="내용 입력"
                            />
                            {log.originalCast && modifiedCast !== log.originalCast && (
                                <p className="mt-1 text-xs text-stone-400">원본: {log.originalCast}</p>
                            )}
                        </div>
                    </div>

                    {/* Footer */}
                    <div className="px-6 py-4 border-t border-stone-200 bg-stone-50 flex justify-between">
                        <div>
                            {log.isOverridden && (
                                <button
                                    onClick={handleReset}
                                    disabled={saving}
                                    className="px-4 py-2 text-amber-600 hover:text-amber-700 text-sm font-medium disabled:opacity-50"
                                >
                                    원본으로 복원
                                </button>
                            )}
                        </div>
                        <div className="flex gap-2">
                            <button
                                onClick={onClose}
                                className="px-4 py-2 bg-stone-200 text-stone-700 rounded-lg hover:bg-stone-300 text-sm font-medium"
                            >
                                취소
                            </button>
                            <button
                                onClick={handleSave}
                                disabled={saving}
                                className="px-4 py-2 bg-emerald-600 text-white rounded-lg hover:bg-emerald-700 text-sm font-medium disabled:opacity-50"
                            >
                                {saving ? '저장 중...' : '저장'}
                            </button>
                        </div>
                    </div>
                </div>
            </div>
        );
    };

    // BankSplitModal Component - 계좌 입출금 분개 모달
    const BankSplitModal = ({ 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) {
                if (existingSplits && existingSplits.length > 0) {
                    // 기존 분개 로드
                    setSplits(existingSplits.map(s => ({
                        amount: parseFloat(s.split_amount || s.amount || 0),
                        accountCode: s.account_code || s.accountCode || '',
                        accountName: s.account_name || s.accountName || '',
                        description: s.description || '',
                        memo: s.memo || ''
                    })));
                } else {
                    // 새 분개: 원본 금액으로 1개 행 생성
                    const origAmount = log.deposit > 0 ? log.deposit : log.withdraw;
                    setSplits([{
                        amount: origAmount,
                        accountCode: log.accountCode || '',
                        accountName: log.accountName || '',
                        description: log.summary || '',
                        memo: ''
                    }]);
                }
            }
        }, [isOpen, log, existingSplits]);

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

        const originalAmount = log.deposit > 0 ? log.deposit : log.withdraw;
        const isDeposit = log.deposit > 0;
        const splitTotal = splits.reduce((sum, s) => sum + (parseFloat(s.amount) || 0), 0);
        const isValid = Math.abs(originalAmount - splitTotal) < 0.01;

        const addSplit = () => {
            const remaining = originalAmount - splitTotal;
            setSplits([...splits, {
                amount: remaining > 0 ? remaining : 0,
                accountCode: '',
                accountName: '',
                description: '',
                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.summary || '-'}</span>
                            </div>
                            <div className="flex justify-between mb-1">
                                <span className="text-stone-500">거래일시</span>
                                <span className="font-medium">{log.transDateTime || '-'}</span>
                            </div>
                            <div className="flex justify-between">
                                <span className="text-stone-500">{isDeposit ? '입금액' : '출금액'}</span>
                                <span className={`font-bold ${isDeposit ? 'text-blue-600' : 'text-red-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) => (
                                <div key={index} className="flex items-start gap-3 p-3 bg-stone-50 rounded-lg">
                                    <div className="flex-1 grid grid-cols-2 gap-3">
                                        <div>
                                            <label className="block text-xs text-stone-500 mb-1">금액 <span className="text-red-500">*</span></label>
                                            <input
                                                type="text"
                                                value={formatAmountInput(split.amount)}
                                                onChange={(e) => updateSplit(index, { amount: 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-emerald-500 outline-none"
                                                placeholder="0"
                                            />
                                        </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-emerald-500 outline-none"
                                            />
                                        </div>
                                        <div>
                                            <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-emerald-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-emerald-400 hover:text-emerald-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-emerald-600 text-white rounded-lg hover:bg-emerald-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                            >
                                {saving ? '저장 중...' : '분개 저장'}
                            </button>
                        </div>
                    </div>
                </div>
            </div>
        );
    };

    // ManualEntryModal Component (수동입력 모달)
    const ManualEntryModal = ({ isOpen, onClose, onSave, editData, accounts, logs }) => {
        const [form, setForm] = useState({});
        const [saving, setSaving] = useState(false);
        const [baseBalance, setBaseBalance] = useState(0);
        const [focusedField, setFocusedField] = useState(null);

        const isEditMode = !!editData;

        // 거래일 기준으로 해당 계좌의 직전 거래 잔액 찾기
        const findBaseBalanceByDate = (accountNum, transDate, transTime) => {
            if (!accountNum || !logs || logs.length === 0) return 0;
            const targetDt = (transDate || '') + (transTime || '000000');
            // 같은 계좌의 거래만 필터 (수정 중인 건은 제외)
            const accountLogs = logs.filter(l =>
                l.bankAccountNum === accountNum &&
                !(editData && l.isManual && l.dbId === editData.dbId)
            );
            if (accountLogs.length === 0) return 0;
            // logs는 날짜 내림차순 정렬 → 입력일보다 이전인 첫 번째 거래의 잔액이 기준
            for (const log of accountLogs) {
                const logDt = (log.transDate || '') + (log.transTime || '');
                if (logDt < targetDt) {
                    return log.balance || 0;
                }
            }
            return 0;
        };

        // 기준잔액 재계산 (계좌, 날짜, 시간 변경 시)
        const recalcBase = (accountNum, transDate, transTime) => {
            const base = findBaseBalanceByDate(accountNum, transDate, transTime);
            setBaseBalance(base);
            return base;
        };

        useEffect(() => {
            if (isOpen) {
                if (editData) {
                    const isRegisteredAccount = accounts.some(a => a.bankAccountNum === editData.bankAccountNum);
                    // 수정 모드: 직전 거래 잔액을 찾아서 기준잔액으로 설정
                    const base = findBaseBalanceByDate(editData.bankAccountNum, editData.transDate, editData.transTime);
                    setBaseBalance(base);
                    setForm({
                        bank_account_num: editData.bankAccountNum || '',
                        bank_code: editData.bankCode || '',
                        bank_name: editData.bankName || '',
                        _manualAccount: !isRegisteredAccount,
                        trans_date: editData.transDate || '',
                        trans_time: editData.transTime || '',
                        trans_type: editData.deposit > 0 ? 'deposit' : 'withdraw',
                        amount: editData.deposit > 0 ? editData.deposit : editData.withdraw,
                        balance: editData.balance || 0,
                        summary: editData.summary || '',
                        cast: editData.cast || '',
                        memo: editData.memo || '',
                        trans_office: editData.transOffice || '',
                    });
                } else {
                    const today = new Date();
                    const todayStr = today.getFullYear() +
                        String(today.getMonth() + 1).padStart(2, '0') +
                        String(today.getDate()).padStart(2, '0');
                    setBaseBalance(0);
                    setForm({
                        bank_account_num: '',
                        bank_code: '',
                        bank_name: '',
                        _manualAccount: false,
                        trans_date: todayStr,
                        trans_time: '',
                        trans_type: 'withdraw',
                        amount: 0,
                        balance: 0,
                        summary: '',
                        cast: '',
                        memo: '',
                        trans_office: '',
                    });
                }
            }
        }, [isOpen, editData]);

        const handleSubmit = async () => {
            if (!form.bank_account_num || !form.trans_date || form.amount === '' || form.amount === 0) {
                notify('계좌번호, 거래일, 금액을 입력해주세요.', 'error');
                return;
            }
            setSaving(true);
            const submitData = {
                bank_account_num: form.bank_account_num,
                bank_code: form.bank_code,
                bank_name: form.bank_name,
                trans_date: form.trans_date,
                trans_time: form.trans_time || '',
                deposit: form.trans_type === 'deposit' ? Number(form.amount) : 0,
                withdraw: form.trans_type === 'withdraw' ? Number(form.amount) : 0,
                balance: Number(form.balance) || 0,
                summary: form.summary,
                cast: form.cast,
                memo: form.memo,
                trans_office: form.trans_office,
            };
            await onSave(submitData, editData?.dbId);
            setSaving(false);
        };

        // 잔액 자동 계산
        const calcBalance = (base, transType, amount) => {
            const amt = Number(amount) || 0;
            return transType === 'deposit' ? base + amt : base - amt;
        };

        const handleAccountSelect = (accNum) => {
            if (accNum === '__manual__') {
                setBaseBalance(0);
                setForm(prev => {
                    const newBal = calcBalance(0, prev.trans_type, prev.amount);
                    return { ...prev, bank_account_num: '', bank_code: '', bank_name: '', _manualAccount: true, balance: newBal };
                });
            } else {
                const acc = accounts.find(a => a.bankAccountNum === accNum);
                if (acc) {
                    setForm(prev => {
                        const base = recalcBase(acc.bankAccountNum, prev.trans_date, prev.trans_time);
                        const newBalance = calcBalance(base, prev.trans_type, prev.amount);
                        return {
                            ...prev,
                            bank_account_num: acc.bankAccountNum,
                            bank_code: acc.bankCode || '',
                            bank_name: acc.bankName || '',
                            _manualAccount: false,
                            balance: newBalance,
                        };
                    });
                }
            }
        };

        // 거래일 변경 시 기준잔액 재계산
        const handleDateChange = (field, value) => {
            setForm(prev => {
                const newForm = { ...prev, [field]: value };
                const base = recalcBase(newForm.bank_account_num, newForm.trans_date, newForm.trans_time);
                const newBalance = calcBalance(base, newForm.trans_type, newForm.amount);
                return { ...newForm, balance: newBalance };
            });
        };

        const formatAmount = (val) => {
            const num = String(val).replace(/[^\d]/g, '');
            return num ? Number(num).toLocaleString() : '';
        };

        const handleAmountChange = (field, value) => {
            const num = String(value).replace(/[^\d]/g, '');
            const numVal = num ? Number(num) : 0;
            if (field === 'amount') {
                const newBalance = calcBalance(baseBalance, form.trans_type, numVal);
                setForm(prev => ({ ...prev, amount: numVal, balance: newBalance }));
            } else {
                setForm(prev => ({ ...prev, [field]: numVal }));
            }
        };

        const handleTransTypeChange = (newType) => {
            const newBalance = calcBalance(baseBalance, newType, form.amount);
            setForm(prev => ({ ...prev, trans_type: newType, balance: newBalance }));
        };

        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-xl shadow-2xl w-full max-w-lg max-h-[90vh] overflow-y-auto">
                    {/* Header */}
                    <div className="flex items-center justify-between px-6 py-4 border-b border-stone-200 bg-emerald-50">
                        <h2 className="text-lg font-bold text-stone-900">
                            {isEditMode ? '수동 거래 수정' : '수동 거래 등록'}
                        </h2>
                        <button onClick={onClose} className="text-stone-400 hover:text-stone-600 text-2xl">&times;</button>
                    </div>

                    {/* Form */}
                    <div className="px-6 py-4 space-y-4">
                        {/* 계좌 선택 */}
                        <div>
                            <label className="block text-sm font-medium text-stone-700 mb-1">계좌 <span className="text-red-500">*</span></label>
                            <select
                                value={form._manualAccount ? '__manual__' : form.bank_account_num}
                                onChange={(e) => handleAccountSelect(e.target.value)}
                                className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                            >
                                <option value="">계좌 선택</option>
                                {accounts.map(acc => (
                                    <option key={acc.bankAccountNum} value={acc.bankAccountNum}>
                                        {acc.bankName} {acc.bankAccountNum}
                                    </option>
                                ))}
                                <option value="__manual__">직접 입력</option>
                            </select>
                            {form._manualAccount && (
                                <div className="mt-2 grid grid-cols-2 gap-2">
                                    <input
                                        type="text"
                                        value={form.bank_name}
                                        onChange={(e) => setForm(prev => ({ ...prev, bank_name: e.target.value }))}
                                        placeholder="은행명"
                                        className="px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                                    />
                                    <input
                                        type="text"
                                        value={form.bank_account_num}
                                        onChange={(e) => setForm(prev => ({ ...prev, bank_account_num: e.target.value }))}
                                        placeholder="계좌번호"
                                        className="px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                                    />
                                </div>
                            )}
                        </div>

                        {/* 거래일 / 거래시간 */}
                        <div className="grid grid-cols-2 gap-4">
                            <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.trans_date || ''}
                                    onChange={(e) => handleDateChange('trans_date', e.target.value.replace(/[^\d]/g, '').slice(0, 8))}
                                    placeholder="YYYYMMDD"
                                    maxLength={8}
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                                />
                            </div>
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">거래시간</label>
                                <input
                                    type="text"
                                    value={form.trans_time || ''}
                                    onChange={(e) => handleDateChange('trans_time', e.target.value.replace(/[^\d]/g, '').slice(0, 6))}
                                    placeholder="HHMMSS"
                                    maxLength={6}
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                                />
                            </div>
                        </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">
                                <label className="flex items-center gap-2 cursor-pointer">
                                    <input
                                        type="radio"
                                        name="trans_type"
                                        value="deposit"
                                        checked={form.trans_type === 'deposit'}
                                        onChange={() => handleTransTypeChange('deposit')}
                                        className="text-blue-600"
                                    />
                                    <span className="text-sm text-blue-600 font-medium">입금</span>
                                </label>
                                <label className="flex items-center gap-2 cursor-pointer">
                                    <input
                                        type="radio"
                                        name="trans_type"
                                        value="withdraw"
                                        checked={form.trans_type === 'withdraw'}
                                        onChange={() => handleTransTypeChange('withdraw')}
                                        className="text-red-600"
                                    />
                                    <span className="text-sm text-red-600 font-medium">출금</span>
                                </label>
                            </div>
                        </div>

                        {/* 금액 / 잔액 */}
                        <div className="grid grid-cols-2 gap-4">
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">금액 <span className="text-red-500">*</span></label>
                                <input
                                    type="text"
                                    value={focusedField === 'amount' && form.amount === 0 ? '' : formatAmount(form.amount)}
                                    onChange={(e) => handleAmountChange('amount', e.target.value)}
                                    onFocus={() => setFocusedField('amount')}
                                    onBlur={() => setFocusedField(null)}
                                    placeholder="금액 입력"
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none text-right"
                                />
                            </div>
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">
                                    잔액 <span className="text-xs text-stone-400 font-normal">(자동계산)</span>
                                </label>
                                <input
                                    type="text"
                                    value={focusedField === 'balance' && form.balance === 0 ? '' : formatAmount(form.balance)}
                                    onChange={(e) => handleAmountChange('balance', e.target.value)}
                                    onFocus={() => setFocusedField('balance')}
                                    onBlur={() => setFocusedField(null)}
                                    placeholder="잔액"
                                    className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none text-right bg-stone-50"
                                />
                                {baseBalance !== 0 && (
                                    <p className="mt-1 text-xs text-stone-400">
                                        기준 잔액: {Number(baseBalance).toLocaleString()}원
                                    </p>
                                )}
                            </div>
                        </div>

                        {/* 적요 */}
                        <div>
                            <label className="block text-sm font-medium text-stone-700 mb-1">적요</label>
                            <input
                                type="text"
                                value={form.summary || ''}
                                onChange={(e) => setForm(prev => ({ ...prev, summary: e.target.value }))}
                                placeholder="적요 입력"
                                className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                            />
                        </div>

                        {/* 상대계좌예금주명 */}
                        <div>
                            <label className="block text-sm font-medium text-stone-700 mb-1">상대계좌예금주명</label>
                            <input
                                type="text"
                                value={form.cast || ''}
                                onChange={(e) => setForm(prev => ({ ...prev, cast: e.target.value }))}
                                placeholder="예금주명 입력"
                                className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                            />
                        </div>

                        {/* 메모 */}
                        <div>
                            <label className="block text-sm font-medium text-stone-700 mb-1">메모</label>
                            <input
                                type="text"
                                value={form.memo || ''}
                                onChange={(e) => setForm(prev => ({ ...prev, 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-emerald-500 outline-none"
                            />
                        </div>

                        {/* 취급점 */}
                        <div>
                            <label className="block text-sm font-medium text-stone-700 mb-1">취급점</label>
                            <input
                                type="text"
                                value={form.trans_office || ''}
                                onChange={(e) => setForm(prev => ({ ...prev, trans_office: e.target.value }))}
                                placeholder="취급점 입력"
                                className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                            />
                        </div>

                    </div>

                    {/* Footer */}
                    <div className="px-6 py-4 border-t border-stone-200 bg-stone-50 flex justify-end gap-2">
                        <button
                            onClick={onClose}
                            className="px-4 py-2 bg-stone-200 text-stone-700 rounded-lg hover:bg-stone-300 text-sm font-medium"
                        >
                            취소
                        </button>
                        <button
                            onClick={handleSubmit}
                            disabled={saving}
                            className="px-4 py-2 bg-emerald-600 text-white rounded-lg hover:bg-emerald-700 text-sm font-medium disabled:opacity-50"
                        >
                            {saving ? '저장 중...' : (isEditMode ? '수정' : '등록')}
                        </button>
                    </div>
                </div>
            </div>
        );
    };

    // TransactionTable Component
    const TransactionTable = ({
        logs,
        loading,
        dateFrom,
        dateTo,
        onDateFromChange,
        onDateToChange,
        onThisMonth,
        onLastMonth,
        onMonthOffset,
        onSearch,
        totalCount,
        onCastChange,
        onSave,
        onExport,
        saving,
        hasChanges,
        onEditTransaction,
        onManualNew,
        onManualEdit,
        onManualDelete,
        onClientCodeChange,
        splits,
        onOpenSplitModal,
        onDeleteSplits
    }) => {
        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-emerald-600"></div>
                </div>
            );
        }

        return (
            <div className="bg-white rounded-xl shadow-sm border border-stone-100 min-h-[calc(100vh-200px)]">
                <div className="p-6 border-b border-stone-100">
                    <div className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4">
                        <h2 className="text-lg font-bold text-stone-900">입출금 내역</h2>
                        {/* 기간 조회 필터 */}
                        <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) => onDateFromChange(e.target.value)}
                                    className="rounded-lg border border-stone-200 px-3 py-1.5 text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                                />
                                <span className="text-stone-400">~</span>
                                <input
                                    type="date"
                                    value={dateTo}
                                    onChange={(e) => onDateToChange(e.target.value)}
                                    className="rounded-lg border border-stone-200 px-3 py-1.5 text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
                                />
                            </div>
                            <div className="flex items-center gap-2">
                                <button
                                    onClick={onThisMonth}
                                    className="px-3 py-1.5 text-sm bg-emerald-50 text-emerald-600 rounded-lg hover:bg-emerald-100 transition-colors font-medium"
                                >
                                    이번 달
                                </button>
                                <button
                                    onClick={onLastMonth}
                                    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={() => onMonthOffset(-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={() => onMonthOffset(-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={() => onMonthOffset(-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={() => onMonthOffset(-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={onSearch}
                                    className="px-4 py-1.5 text-sm bg-emerald-600 text-white rounded-lg hover:bg-emerald-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>건
                                {totalCount !== logs.length && (
                                    <span className="text-stone-400"> / 전체 {totalCount}건</span>
                                )}
                            </span>
                        </div>
                    </div>
                    {/* 저장/엑셀 버튼 */}
                    <div className="flex items-center gap-2 mt-4">
                        <button
                            onClick={onSave}
                            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-emerald-600 text-white hover:bg-emerald-700'
                                    : 'bg-emerald-100 text-emerald-700 hover:bg-emerald-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={onExport}
                            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={onManualNew}
                            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>
                    </div>
                </div>
                <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-2 py-4 bg-stone-50 text-center w-[50px]">번호</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 text-right bg-stone-50 text-blue-600">입금</th>
                                <th className="px-4 py-4 text-right bg-stone-50 text-red-600">출금</th>
                                <th className="px-4 py-4 text-right 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-[120px]">상대계좌예금주명</th>
                                <th className="px-4 py-4 bg-stone-50 min-w-[140px]">거래처코드</th>
                                <th className="px-4 py-4 bg-stone-50 text-center w-[80px]">관리</th>
                            </tr>
                        </thead>
                        <tbody className="divide-y divide-stone-100">
                            {logs.length === 0 ? (
                                <tr>
                                    <td colSpan="11" className="px-6 py-8 text-center text-stone-400">
                                        해당 기간에 조회된 입출금 내역이 없습니다.
                                    </td>
                                </tr>
                            ) : (
                                logs.map((log, index) => {
                                    const logSplits = splits && splits[log.uniqueKey] ? splits[log.uniqueKey] : [];
                                    const hasSplits = logSplits.length > 0;
                                    return (
                                    <React.Fragment key={index}>
                                    <tr className={`hover:bg-stone-50 transition-colors ${log.isSaved ? 'bg-green-50/30' : ''} ${log.isOverridden ? 'bg-amber-50/50' : ''}`}>
                                        <td className="px-2 py-3 text-center text-xs text-stone-500 font-medium">
                                            {index + 1}
                                        </td>
                                        <td className="px-4 py-3 whitespace-nowrap">
                                            <div className="font-medium text-stone-900">{log.transDateTime || '-'}</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.bankName}</div>
                                            <div className="text-xs text-stone-400 font-mono">
                                                {log.bankAccountNum ? '****' + log.bankAccountNum.slice(-4) : '-'}
                                            </div>
                                        </td>
                                        <td
                                            className="px-4 py-3 cursor-pointer hover:bg-emerald-50 group"
                                            onClick={() => onEditTransaction(index)}
                                        >
                                            <div className="flex items-center gap-1">
                                                <div className="font-medium text-stone-900">{log.summary || '-'}</div>
                                                {log.isOverridden && (
                                                    <span className="px-1 py-0.5 bg-amber-100 text-amber-700 text-xs rounded">수정</span>
                                                )}
                                                <svg className="w-3 h-3 text-stone-400 opacity-0 group-hover:opacity-100 transition-opacity" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
                                                </svg>
                                            </div>
                                            {log.memo && <div className="text-xs text-stone-400">{log.memo}</div>}
                                        </td>
                                        <td className="px-4 py-3 text-right font-medium text-blue-600">
                                            {log.deposit > 0 ? log.depositFormatted + '원' : '-'}
                                        </td>
                                        <td className="px-4 py-3 text-right font-medium text-red-600">
                                            {log.withdraw > 0 ? log.withdrawFormatted + '원' : '-'}
                                        </td>
                                        <td className="px-4 py-3 text-right text-stone-700">
                                            {log.balanceFormatted}원
                                        </td>
                                        <td className="px-4 py-3 text-stone-500 text-sm">
                                            {log.transOffice || '-'}
                                        </td>
                                        <td className="px-4 py-3">
                                            <input
                                                type="text"
                                                className="w-full px-2 py-1 text-sm border border-stone-200 rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none"
                                                value={log.cast || ''}
                                                onChange={(e) => onCastChange(index, e.target.value)}
                                                placeholder="예금주명 입력"
                                            />
                                        </td>
                                        <td className="px-4 py-3">
                                            <ClientCodeSelect
                                                value={log.clientCode || ''}
                                                clientName={log.clientName || ''}
                                                onChange={(code, name) => onClientCodeChange(index, code, name)}
                                            />
                                        </td>
                                        <td className="px-3 py-3 text-center">
                                            {log.isManual && (
                                                <div className="flex items-center gap-1 justify-center">
                                                    <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>
                                                </div>
                                            )}
                                        </td>
                                    </tr>
                                    {/* 분개 하위 행 */}
                                    {hasSplits && logSplits.map((split, sIdx) => (
                                        <tr key={`${index}-split-${sIdx}`} className="bg-amber-50/30">
                                            <td className="px-2 py-2 text-center">
                                                <svg className="w-4 h-4 text-amber-400 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5l7 7-7 7" />
                                                </svg>
                                            </td>
                                            <td className="px-4 py-2 text-xs text-stone-400" colSpan="2">
                                                <span className="text-amber-600 font-medium">분개 #{sIdx + 1}</span>
                                                {split.memo && <span className="ml-2 text-stone-400">- {split.memo}</span>}
                                            </td>
                                            <td className="px-4 py-2 text-xs text-stone-500">{split.description || '-'}</td>
                                            <td className="px-4 py-2 text-right text-sm font-medium text-blue-600">
                                                {log.deposit > 0 ? new Intl.NumberFormat('ko-KR').format(split.split_amount || 0) + '원' : '-'}
                                            </td>
                                            <td className="px-4 py-2 text-right text-sm font-medium text-red-600">
                                                {log.withdraw > 0 ? new Intl.NumberFormat('ko-KR').format(split.split_amount || 0) + '원' : '-'}
                                            </td>
                                            <td className="px-4 py-2"></td>
                                            <td className="px-4 py-2"></td>
                                            <td className="px-4 py-2"></td>
                                            <td className="px-4 py-2"></td>
                                            <td className="px-3 py-2"></td>
                                        </tr>
                                    ))}
                                    </React.Fragment>
                                    );
                                })
                            )}
                        </tbody>
                    </table>
                </div>
            </div>
        );
    };

    // Main App Component
    const App = () => {
        const [loading, setLoading] = useState(true);
        const [saving, setSaving] = useState(false);
        const [accounts, setAccounts] = useState([]);
        const [selectedAccount, setSelectedAccount] = 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 [showSettingsModal, setShowSettingsModal] = useState(false);
        const [editModalOpen, setEditModalOpen] = useState(false);
        const [editingLogIndex, setEditingLogIndex] = useState(null);
        // 수동입력 관련 상태
        const [manualModalOpen, setManualModalOpen] = useState(false);
        const [manualEditData, setManualEditData] = 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 currentMonth = getMonthDates(0);
        const [dateFrom, setDateFrom] = useState(currentMonth.from);
        const [dateTo, setDateTo] = useState(currentMonth.to);

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

        const loadAccounts = async () => {
            try {
                const response = await fetch(API.accounts);
                const data = await response.json();
                if (data.success) {
                    setAccounts(data.accounts || []);
                }
            } 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, ''),
                    accountNum: selectedAccount,
                    page: page,
                    limit: 50
                });

                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 || {});
                    // 분개 데이터도 함께 로드
                    loadSplits();
                } else {
                    setError(data.error || '조회 실패');
                    setLogs([]);
                }
            } catch (err) {
                setError('서버 통신 오류: ' + err.message);
                setLogs([]);
            } finally {
                setLoading(false);
            }
        };

        // 분개 데이터 로드
        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) {
                    setSplits(data.data || {});
                }
            } catch (err) {
                console.error('분개 데이터 로드 오류:', err);
            }
        };

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

        // 분개 저장
        const handleSaveSplits = async (log, splitData) => {
            try {
                const originalAmount = log.deposit > 0 ? log.deposit : log.withdraw;
                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: log.uniqueKey,
                        originalData: {
                            bankAccountNum: log.bankAccountNum,
                            transDt: log.transDate + (log.transTime || ''),
                            transDate: log.transDate,
                            originalDeposit: log.deposit || 0,
                            originalWithdraw: log.withdraw || 0,
                            originalAmount: originalAmount,
                            summary: log.summary || '',
                        },
                        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) => {
            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) => {
            await handleDeleteSplits(log.uniqueKey);
        };

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

        // 상대계좌예금주명 변경 핸들러
        const handleCastChange = useCallback((index, value) => {
            console.log('[CastChange Debug] index:', index, 'value:', value);
            setLogs(prevLogs => {
                const newLogs = [...prevLogs];
                console.log('[CastChange Debug] 기존 cast:', newLogs[index]?.cast, 'isManual:', newLogs[index]?.isManual, 'dbId:', newLogs[index]?.dbId);
                newLogs[index] = {
                    ...newLogs[index],
                    cast: value
                };
                return newLogs;
            });
            setHasChanges(true);
        }, []);

        // 거래처코드 변경 핸들러
        const handleClientCodeChange = useCallback((index, code, name) => {
            setLogs(prevLogs => {
                const newLogs = [...prevLogs];
                newLogs[index] = {
                    ...newLogs[index],
                    clientCode: code,
                    clientName: name
                };
                return newLogs;
            });
            setHasChanges(true);
        }, []);

        // 거래 수정 모달 열기
        const handleEditTransaction = useCallback((index) => {
            setEditingLogIndex(index);
            setEditModalOpen(true);
        }, []);

        // 오버라이드 저장 후 로그 업데이트
        const handleSaveOverride = useCallback((newSummary, newCast) => {
            if (editingLogIndex !== null) {
                setLogs(prevLogs => {
                    const newLogs = [...prevLogs];
                    newLogs[editingLogIndex] = {
                        ...newLogs[editingLogIndex],
                        summary: newSummary,
                        cast: newCast,
                        isOverridden: true
                    };
                    return newLogs;
                });
            }
        }, [editingLogIndex]);

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

            // 디버그: 저장할 수동 거래 확인
            const manualLogs = logs.filter(l => l.isManual);
            console.log('[Save Debug] 전체 로그 수:', logs.length, '수동 거래 수:', manualLogs.length);
            manualLogs.forEach(l => {
                console.log('[Save Debug] 수동 거래:', {dbId: l.dbId, isManual: l.isManual, cast: l.cast, summary: l.summary});
            });

            setSaving(true);
            try {
                console.log('[Save Debug] API.save URL:', API.save);
                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 })
                });

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

        // 엑셀 다운로드 핸들러
        const handleExport = () => {
            const params = new URLSearchParams({
                startDate: dateFrom.replace(/-/g, ''),
                endDate: dateTo.replace(/-/g, ''),
                accountNum: selectedAccount
            });
            window.location.href = `${API.export}?${params}`;
        };

        // 수동입력 - 새로 등록 열기
        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 handleThisMonth = () => {
            const dates = getMonthDates(0);
            setDateFrom(dates.from);
            setDateTo(dates.to);
        };

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

        // N개월 전 버튼
        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-8">
                {/* Page Header */}
                <div className="flex items-center justify-between">
                    <div>
                        <h1 className="text-2xl font-bold text-stone-900">계좌 입출금내역</h1>
                        <p className="text-stone-500 mt-1">바로빌 API를 통한 계좌 입출금내역 조회</p>
                    </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-stone-100 p-4">
                    <div className="flex flex-wrap items-center gap-3">
                        {/* 통계 배지들 */}
                        <CompactStat label="입금" value={formatCurrency(summary.totalDeposit)} color="blue" />
                        <CompactStat label="출금" value={formatCurrency(summary.totalWithdraw)} color="red" />
                        <CompactStat label="잔액" value={formatCurrency(logs.length > 0 ? logs[0].balance : 0)} color="emerald" />
                        <CompactStat label="계좌" value={`${accounts.length}개`} color="green" />
                        <CompactStat label="거래" value={`${(summary.count || 0).toLocaleString()}건`} color="stone" />

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

                        {/* 계좌 선택 버튼들 */}
                        {accounts.length > 0 && (
                            <>
                                <span className="text-xs text-stone-500">계좌:</span>
                                <AccountSelector
                                    accounts={accounts}
                                    selectedAccount={selectedAccount}
                                    onSelect={setSelectedAccount}
                                />
                            </>
                        )}
                    </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('-50214') && (
                                    <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>
                                            <li>필요시 계좌 재등록 또는 비밀번호 재설정</li>
                                        </ol>
                                    </div>
                                )}
                            </div>
                        </div>
                    </div>
                )}

                {/* Transaction Table */}
                {!error && (
                    <TransactionTable
                        logs={logs}
                        loading={loading}
                        dateFrom={dateFrom}
                        dateTo={dateTo}
                        onDateFromChange={setDateFrom}
                        onDateToChange={setDateTo}
                        onThisMonth={handleThisMonth}
                        onLastMonth={handleLastMonth}
                        onMonthOffset={handleMonthOffset}
                        onSearch={() => loadTransactions()}
                        totalCount={summary.count || logs.length}
                        onCastChange={handleCastChange}
                        onSave={handleSave}
                        onExport={handleExport}
                        saving={saving}
                        hasChanges={hasChanges}
                        onEditTransaction={handleEditTransaction}
                        onManualNew={handleManualNew}
                        onManualEdit={handleManualEdit}
                        onManualDelete={handleManualDelete}
                        onClientCodeChange={handleClientCodeChange}
                        splits={splits}
                        onOpenSplitModal={handleOpenSplitModal}
                        onDeleteSplits={handleDeleteSplits}
                    />
                )}

                {/* Bank Split Modal */}
                <BankSplitModal
                    isOpen={splitModalOpen}
                    onClose={() => { setSplitModalOpen(false); setSplitModalLog(null); setSplitModalExisting([]); }}
                    log={splitModalLog}
                    accountCodes={accountCodes}
                    onSave={handleSaveSplits}
                    onReset={handleResetSplits}
                    splits={splitModalExisting}
                />

                {/* Transaction Edit Modal */}
                <TransactionEditModal
                    isOpen={editModalOpen}
                    onClose={() => {
                        setEditModalOpen(false);
                        setEditingLogIndex(null);
                    }}
                    log={editingLogIndex !== null ? logs[editingLogIndex] : null}
                    onSave={handleSaveOverride}
                />

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


                {/* 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('eaccount-root'));
    root.render(<App />);
</script>
@endpush
