@extends('layouts.app')

@section('title', '홈택스 매출/매입')

@section('content')
<!-- 현재 테넌트 정보 카드 (React 외부) -->
<x-barobill-tenant-header
    :currentTenant="$currentTenant"
    :barobillMember="$barobillMember"
    :isTestMode="$isTestMode"
    gradientFrom="#7c3aed"
    gradientTo="#8b5cf6"
    :icon="'<svg class=&quot;w-7 h-7&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; viewBox=&quot;0 0 24 24&quot;><path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; stroke-width=&quot;2&quot; d=&quot;M9 12h6m-6 4h6m2 5H7a2 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&quot; /></svg>'"
/>

<div id="hometax-root"></div>
@endsection

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

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

    // API Routes
    const API = {
        sales: '{{ route("barobill.hometax.sales") }}',
        purchases: '{{ route("barobill.hometax.purchases") }}',
        localSales: '{{ route("barobill.hometax.local-sales") }}',
        localPurchases: '{{ route("barobill.hometax.local-purchases") }}',
        sync: '{{ route("barobill.hometax.sync") }}',
        autoSync: '{{ route("barobill.hometax.auto-sync") }}',
        updateMemo: '{{ route("barobill.hometax.update-memo") }}',
        toggleChecked: '{{ route("barobill.hometax.toggle-checked") }}',
        requestCollect: '{{ route("barobill.hometax.request-collect") }}',
        collectStatus: '{{ route("barobill.hometax.collect-status") }}',
        export: '{{ route("barobill.hometax.export") }}',
        scrapUrl: '{{ route("barobill.hometax.scrap-url") }}',
        refreshScrap: '{{ route("barobill.hometax.refresh-scrap") }}',
        diagnose: '{{ route("barobill.hometax.diagnose") }}',
        manualStore: '{{ route("barobill.hometax.manual-store") }}',
        manualUpdate: '{{ route("barobill.hometax.manual-update", ["id" => "__ID__"]) }}',
        manualDestroy: '{{ route("barobill.hometax.manual-destroy", ["id" => "__ID__"]) }}',
        createJournalEntry: '{{ route("barobill.hometax.create-journal-entry") }}',
        journals: '{{ route("barobill.hometax.journals") }}',
        deleteJournals: '{{ route("barobill.hometax.journals.delete") }}',
        cardTransactions: '{{ route("barobill.hometax.card-transactions") }}',
        accountCodes: '{{ route("barobill.ecard.account-codes") }}',
    };

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

    // 한국 시간대(Asia/Seoul, UTC+9) 기준 날짜 포맷 (YYYY-MM-DD)
    const formatKoreanDate = (date) => {
        // en-CA 로케일은 YYYY-MM-DD 형식을 반환함
        return date.toLocaleDateString('en-CA', { timeZone: 'Asia/Seoul' });
    };

    // 한국 시간대 기준 현재 날짜 가져오기
    const getKoreanNow = () => {
        const koreaDateStr = new Date().toLocaleString('en-US', { timeZone: 'Asia/Seoul' });
        return new Date(koreaDateStr);
    };

    // 날짜 유틸리티 함수 - 한국 시간대(Asia/Seoul) 기준
    const getMonthDates = (offset = 0) => {
        const now = getKoreanNow();
        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: formatKoreanDate(firstDay),
            to: formatKoreanDate(lastDay)
        };
    };

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

    // StatCard Component
    const StatCard = ({ title, value, subtext, icon, color = 'purple' }) => {
        const colorClasses = {
            purple: 'bg-purple-50 text-purple-600',
            blue: 'bg-blue-50 text-blue-600',
            green: 'bg-green-50 text-green-600',
            red: 'bg-red-50 text-red-600',
            amber: 'bg-amber-50 text-amber-600',
            stone: 'bg-stone-50 text-stone-600'
        };
        return (
            <div className="bg-white rounded-xl p-6 shadow-sm border border-stone-100 hover:shadow-md transition-shadow">
                <div className="flex items-start justify-between mb-4">
                    <h3 className="text-sm font-medium text-stone-500">{title}</h3>
                    <div className={`p-2 rounded-lg ${colorClasses[color] || colorClasses.purple}`}>
                        {icon}
                    </div>
                </div>
                <div className="text-2xl font-bold text-stone-900 mb-1">{value}</div>
                {subtext && <div className="text-xs text-stone-400">{subtext}</div>}
            </div>
        );
    };

    // Tab Component
    const TabButton = ({ active, onClick, children, badge }) => (
        <button
            onClick={onClick}
            className={`px-6 py-3 text-sm font-medium rounded-lg transition-all ${
                active
                    ? 'bg-purple-600 text-white shadow-lg shadow-purple-200'
                    : 'bg-white text-stone-600 hover:bg-stone-50 border border-stone-200'
            }`}
        >
            <span className="flex items-center gap-2">
                {children}
                {badge !== undefined && (
                    <span className={`px-2 py-0.5 rounded-full text-xs ${
                        active ? 'bg-white/20 text-white' : 'bg-stone-100 text-stone-600'
                    }`}>
                        {badge}
                    </span>
                )}
            </span>
        </button>
    );

    // InvoiceTable Component - 홈택스 원본 형태
    const InvoiceTable = ({
        invoices,
        loading,
        type,
        onExport,
        onRequestCollect,
        summary,
        onJournalEntry,
        onEditManual,
        onDeleteManual
    }) => {
        const formatCurrency = (val) => new Intl.NumberFormat('ko-KR').format(val || 0);

        if (loading) {
            return (
                <div className="flex items-center justify-center py-20">
                    <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-purple-600"></div>
                    <span className="ml-3 text-stone-500">홈택스 데이터 조회 중...</span>
                </div>
            );
        }

        const isExpense = type === 'purchase';

        return (
            <div className="bg-white rounded-xl shadow-sm border border-stone-200 overflow-hidden">
                <div className="p-4 border-b border-stone-200 bg-stone-50">
                    <div className="flex items-center justify-between">
                        <h2 className="text-lg font-bold text-stone-800">
                            {isExpense ? '매입 세금계산서' : '매출 세금계산서'}
                        </h2>
                        <div className="flex items-center gap-2">
                            <button
                                onClick={onRequestCollect}
                                className="flex items-center gap-2 px-3 py-1.5 bg-purple-600 text-white rounded text-sm font-medium hover:bg-purple-700 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="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
                                </svg>
                                수집 요청
                            </button>
                            <button
                                onClick={onExport}
                                disabled={invoices.length === 0}
                                className="flex items-center gap-2 px-3 py-1.5 bg-blue-100 text-blue-700 rounded 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>
                            <span className="text-sm text-stone-500 ml-2">
                                <span className="font-semibold text-stone-700">{invoices.length}</span>건
                            </span>
                        </div>
                    </div>
                </div>
                <div className="overflow-x-auto">
                    <table className="w-full text-sm border-collapse">
                        {/* 홈택스 스타일 테이블 헤더 */}
                        <thead>
                            <tr className="bg-[#f8f9fa] border-b-2 border-[#dee2e6]">
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] border-r border-[#dee2e6] whitespace-nowrap">구분</th>
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] border-r border-[#dee2e6] whitespace-nowrap">작성일자</th>
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] border-r border-[#dee2e6] whitespace-nowrap">발급일자</th>
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] border-r border-[#dee2e6] whitespace-nowrap">거래처</th>
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] border-r border-[#dee2e6] whitespace-nowrap">사업자번호<br/>(주민번호)</th>
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] border-r border-[#dee2e6] whitespace-nowrap">과세<br/>형태</th>
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] border-r border-[#dee2e6] whitespace-nowrap">품목</th>
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] border-r border-[#dee2e6] whitespace-nowrap">공급가액</th>
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] border-r border-[#dee2e6] whitespace-nowrap">세액</th>
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] border-r border-[#dee2e6] whitespace-nowrap">합계</th>
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] border-r border-[#dee2e6] whitespace-nowrap">영수<br/>청구</th>
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] border-r border-[#dee2e6] whitespace-nowrap">문서<br/>형태</th>
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] border-r border-[#dee2e6] whitespace-nowrap">발급<br/>형태</th>
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] border-r border-[#dee2e6] whitespace-nowrap">상태</th>
                                <th className="px-3 py-3 text-center text-xs font-semibold text-[#495057] whitespace-nowrap">액션</th>
                            </tr>
                        </thead>
                        <tbody>
                            {invoices.length === 0 ? (
                                <tr>
                                    <td colSpan="15" className="px-6 py-8 text-center text-stone-400 border-b border-[#dee2e6]">
                                        해당 기간에 조회된 세금계산서가 없습니다.
                                    </td>
                                </tr>
                            ) : (
                                invoices.map((inv, index) => {
                                    // 발급일자 포맷팅
                                    const issueDateFormatted = inv.issueDT && inv.issueDT.length >= 8
                                        ? `${inv.issueDT.substring(0,4)}-${inv.issueDT.substring(4,6)}-${inv.issueDT.substring(6,8)}`
                                        : inv.writeDateFormatted || '-';

                                    return (
                                        <tr key={index} className="hover:bg-[#f1f3f5] border-b border-[#dee2e6]">
                                            {/* 구분 */}
                                            <td className="px-3 py-2.5 text-center border-r border-[#dee2e6]">
                                                {inv.ntsConfirmNum && inv.ntsConfirmNum.startsWith('MAN-') ? (
                                                    <span className="text-[#7c3aed] text-xs font-medium">수동</span>
                                                ) : (
                                                    <span className="text-[#0d6efd] text-xs font-medium">홈택</span>
                                                )}
                                            </td>
                                            {/* 작성일자 */}
                                            <td className="px-3 py-2.5 text-center text-[#212529] text-xs border-r border-[#dee2e6] whitespace-nowrap">
                                                {inv.writeDateFormatted || '-'}
                                            </td>
                                            {/* 발급일자 */}
                                            <td className="px-3 py-2.5 text-center text-[#212529] text-xs border-r border-[#dee2e6] whitespace-nowrap">
                                                {issueDateFormatted}
                                            </td>
                                            {/* 거래처 */}
                                            <td className="px-3 py-2.5 text-left text-[#212529] text-xs border-r border-[#dee2e6] max-w-[200px] truncate">
                                                {isExpense ? inv.invoicerCorpName : inv.invoiceeCorpName}
                                            </td>
                                            {/* 사업자번호 */}
                                            <td className="px-3 py-2.5 text-center text-[#212529] text-xs border-r border-[#dee2e6] whitespace-nowrap font-mono">
                                                {isExpense ? inv.invoicerCorpNum : inv.invoiceeCorpNum}
                                            </td>
                                            {/* 과세형태 */}
                                            <td className="px-3 py-2.5 text-center border-r border-[#dee2e6]">
                                                <span className={`text-xs ${
                                                    inv.taxTypeName === '면세' ? 'text-[#e91e63]' : 'text-[#212529]'
                                                }`}>
                                                    {inv.taxTypeName || '-'}
                                                </span>
                                            </td>
                                            {/* 품목 */}
                                            <td className="px-3 py-2.5 text-left text-[#212529] text-xs border-r border-[#dee2e6] max-w-[150px] truncate" title={inv.itemName || ''}>
                                                {inv.itemName || '-'}
                                            </td>
                                            {/* 공급가액 */}
                                            <td className="px-3 py-2.5 text-right text-[#212529] text-xs border-r border-[#dee2e6] whitespace-nowrap font-medium">
                                                {formatCurrency(inv.supplyAmount)}
                                            </td>
                                            {/* 세액 */}
                                            <td className="px-3 py-2.5 text-right text-[#212529] text-xs border-r border-[#dee2e6] whitespace-nowrap">
                                                {formatCurrency(inv.taxAmount)}
                                            </td>
                                            {/* 합계 */}
                                            <td className="px-3 py-2.5 text-right text-[#0d6efd] text-xs border-r border-[#dee2e6] whitespace-nowrap font-bold">
                                                {formatCurrency(inv.totalAmount)}
                                            </td>
                                            {/* 영수청구 */}
                                            <td className="px-3 py-2.5 text-center text-[#212529] text-xs border-r border-[#dee2e6]">
                                                {inv.purposeTypeName || '-'}
                                            </td>
                                            {/* 문서형태 */}
                                            <td className="px-3 py-2.5 text-center text-[#212529] text-xs border-r border-[#dee2e6]">
                                                일반
                                            </td>
                                            {/* 발급형태 */}
                                            <td className="px-3 py-2.5 text-center text-[#212529] text-xs border-r border-[#dee2e6]">
                                                정발급
                                            </td>
                                            {/* 상태 */}
                                            <td className="px-3 py-2.5 text-center border-r border-[#dee2e6]">
                                                {inv.ntsConfirmNum && inv.ntsConfirmNum.startsWith('MAN-') ? (
                                                    <span className="text-[#7c3aed] text-xs font-medium">수동입력</span>
                                                ) : (
                                                    <span className="text-[#198754] text-xs font-medium">전송완료</span>
                                                )}
                                            </td>
                                            {/* 액션 */}
                                            <td className="px-2 py-2.5 text-center">
                                                <div className="flex items-center justify-center gap-1">
                                                    <button
                                                        onClick={() => onJournalEntry && onJournalEntry(inv)}
                                                        className={`px-2 py-1 rounded text-xs transition-colors ${inv.hasJournal ? 'bg-emerald-600 text-white hover:bg-emerald-700' : 'bg-emerald-50 text-emerald-700 hover:bg-emerald-100'}`}
                                                        title={inv.hasJournal ? "분개 수정" : "분개 생성"}
                                                    >{inv.hasJournal ? '분개완료' : '분개'}</button>
                                                    {inv.ntsConfirmNum && inv.ntsConfirmNum.startsWith('MAN-') && (
                                                        <>
                                                            <button
                                                                onClick={() => onEditManual && onEditManual(inv)}
                                                                className="px-2 py-1 bg-blue-50 text-blue-700 rounded text-xs hover:bg-blue-100 transition-colors"
                                                                title="수정"
                                                            >수정</button>
                                                            <button
                                                                onClick={() => onDeleteManual && onDeleteManual(inv)}
                                                                className="px-2 py-1 bg-red-50 text-red-700 rounded text-xs hover:bg-red-100 transition-colors"
                                                                title="삭제"
                                                            >삭제</button>
                                                        </>
                                                    )}
                                                </div>
                                            </td>
                                        </tr>
                                    );
                                })
                            )}
                            {/* 합계행 */}
                            {invoices.length > 0 && summary && (
                                <tr className="bg-[#e7f1ff] border-t-2 border-[#0d6efd]">
                                    <td colSpan="7" className="px-3 py-3 text-center text-sm font-bold text-[#0d6efd] border-r border-[#dee2e6]">
                                        합계 ({invoices.length}건)
                                    </td>
                                    <td className="px-3 py-3 text-right text-sm font-bold text-[#212529] border-r border-[#dee2e6]">
                                        {formatCurrency(summary.supplyAmount)}
                                    </td>
                                    <td className="px-3 py-3 text-right text-sm font-bold text-[#212529] border-r border-[#dee2e6]">
                                        {formatCurrency(summary.taxAmount)}
                                    </td>
                                    <td className="px-3 py-3 text-right text-sm font-bold text-[#0d6efd] border-r border-[#dee2e6]">
                                        {formatCurrency(summary.totalAmount)}
                                    </td>
                                    <td colSpan="5" className="px-3 py-3"></td>
                                </tr>
                            )}
                        </tbody>
                    </table>
                </div>
            </div>
        );
    };

    // Main App Component
    const App = () => {
        const [activeTab, setActiveTab] = useState('sales'); // sales or purchase
        const [loading, setLoading] = useState(true);
        const [salesData, setSalesData] = useState({ invoices: [], summary: {}, pagination: {}, loaded: false });
        const [purchaseData, setPurchaseData] = useState({ invoices: [], summary: {}, pagination: {}, loaded: false });
        const [error, setError] = useState(null);
        const [collectStatus, setCollectStatus] = useState(null);

        // 날짜 필터 상태 (기본: 현재 월)
        const currentMonth = getMonthDates(0);
        const [dateFrom, setDateFrom] = useState(currentMonth.from);
        const [dateTo, setDateTo] = useState(currentMonth.to);
        const [dateType, setDateType] = useState('write'); // 'write': 작성일자, 'issue': 발급일자
        const [searchCorpName, setSearchCorpName] = useState(''); // 거래처 검색
        const [autoSyncing, setAutoSyncing] = useState(false); // 자동 동기화 중 여부
        const [lastSyncAt, setLastSyncAt] = useState({ sales: null, purchase: null }); // 마지막 동기화 시간
        const [selectedPeriod, setSelectedPeriod] = useState(null); // 선택된 기간 버튼 ('q1', 'q2', 'q3', 'q4', 'h1', 'h2', 'year')

        // 진단 관련 상태
        const [showDiagnoseModal, setShowDiagnoseModal] = useState(false);
        const [diagnoseResult, setDiagnoseResult] = useState(null);
        const [diagnosing, setDiagnosing] = useState(false);

        // 수동입력 모달
        const [showManualModal, setShowManualModal] = useState(false);
        const [manualEditData, setManualEditData] = useState(null);

        // 거래처 관련
        const [tradingPartners, setTradingPartners] = useState([]);
        const [showAddPartnerModal, setShowAddPartnerModal] = useState(false);

        // 분개 모달
        const [showJournalModal, setShowJournalModal] = useState(false);
        const [journalInvoice, setJournalInvoice] = useState(null);

        // 계정과목 목록
        const [accountCodes, setAccountCodes] = useState([]);

        // 초기 로드 (매출만 먼저 조회)
        useEffect(() => {
            loadSalesData();
            loadCollectStatus();
            fetchTradingPartners();
            loadAccountCodes();
            // 초기 로드 후 자동 동기화 (매출)
            triggerAutoSync('sales');
        }, []);

        // 탭 변경 시 해당 탭 데이터 로드 (아직 로드되지 않은 경우)
        useEffect(() => {
            if (activeTab === 'sales' && !salesData.loaded) {
                loadSalesData();
            } else if (activeTab === 'purchase' && !purchaseData.loaded) {
                loadPurchaseData();
            }
            // 탭 전환 시 해당 탭 자동 동기화
            triggerAutoSync(activeTab === 'sales' ? 'sales' : 'purchase');
        }, [activeTab]);

        // 매출 데이터 로드
        const loadSalesData = async () => {
            setLoading(true);
            setError(null);

            // dateType: 1=작성일자, 2=발급일자, 3=전송일자
            const dateTypeCode = dateType === 'write' ? 1 : 2;
            const params = new URLSearchParams({
                startDate: dateFrom.replace(/-/g, ''),
                endDate: dateTo.replace(/-/g, ''),
                dateType: dateTypeCode,
                searchCorp: searchCorpName,
                limit: 500
            });

            try {
                const res = await fetch(`${API.localSales}?${params}`);
                const json = await res.json();

                if (json.success) {
                    setSalesData({
                        invoices: json.data?.invoices || [],
                        summary: json.data?.summary || {},
                        pagination: json.data?.pagination || {},
                        loaded: true
                    });
                    // 마지막 동기화 시간 업데이트
                    if (json.lastSyncAt) {
                        setLastSyncAt(prev => ({ ...prev, sales: json.lastSyncAt }));
                    }
                    // 마지막 수집 시간 갱신
                    loadCollectStatus();
                } else {
                    setError(json.error || '매출 조회 실패');
                }
            } catch (err) {
                setError('서버 통신 오류: ' + err.message);
            } finally {
                setLoading(false);
            }
        };

        // 매입 데이터 로드
        const loadPurchaseData = async () => {
            setLoading(true);
            setError(null);

            // dateType: 1=작성일자, 2=발급일자, 3=전송일자
            const dateTypeCode = dateType === 'write' ? 1 : 2;
            const params = new URLSearchParams({
                startDate: dateFrom.replace(/-/g, ''),
                endDate: dateTo.replace(/-/g, ''),
                dateType: dateTypeCode,
                searchCorp: searchCorpName,
                limit: 500
            });

            try {
                const res = await fetch(`${API.localPurchases}?${params}`);
                const json = await res.json();

                if (json.success) {
                    setPurchaseData({
                        invoices: json.data?.invoices || [],
                        summary: json.data?.summary || {},
                        pagination: json.data?.pagination || {},
                        loaded: true
                    });
                    // 마지막 동기화 시간 업데이트
                    if (json.lastSyncAt) {
                        setLastSyncAt(prev => ({ ...prev, purchase: json.lastSyncAt }));
                    }
                    // 마지막 수집 시간 갱신
                    loadCollectStatus();
                } else {
                    setError(json.error || '매입 조회 실패');
                }
            } catch (err) {
                setError('서버 통신 오류: ' + err.message);
            } finally {
                setLoading(false);
            }
        };

        // 현재 탭 데이터 로드 (조회 버튼용)
        const loadCurrentTabData = () => {
            // loaded 플래그 초기화 (탭 전환 시에도 새 날짜로 재조회되도록)
            setSalesData(prev => ({ ...prev, loaded: false }));
            setPurchaseData(prev => ({ ...prev, loaded: false }));

            if (activeTab === 'sales') {
                loadSalesData();
            } else {
                loadPurchaseData();
            }
        };

        // 자동 증분 동기화
        const triggerAutoSync = async (type) => {
            setAutoSyncing(true);
            try {
                const res = await fetch(API.autoSync, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN
                    },
                    body: JSON.stringify({ type })
                });
                const json = await res.json();

                if (json.success && !json.skipped && json.hasNewData) {
                    // 신규 데이터가 있으면 화면 갱신
                    if (type === 'sales') {
                        loadSalesData();
                    } else {
                        loadPurchaseData();
                    }
                    notify(`${json.data.inserted}건 추가, ${json.data.updated}건 갱신`, 'success');
                }

                // 마지막 동기화 시간 업데이트
                if (json.lastSyncAt) {
                    setLastSyncAt(prev => ({ ...prev, [type]: json.lastSyncAt }));
                }
            } catch (err) {
                console.error('자동 동기화 오류:', err);
                // 자동동기화 실패는 사용자에게 알리지 않음
            } finally {
                setAutoSyncing(false);
            }
        };

        const loadCollectStatus = async () => {
            try {
                const res = await fetch(API.collectStatus);
                const data = await res.json();
                if (data.success) {
                    setCollectStatus(data.data);
                }
            } catch (err) {
                console.error('수집 상태 조회 오류:', err);
            }
        };

        const fetchTradingPartners = async () => {
            try {
                const res = await fetch('/finance/journal-entries/trading-partners');
                const data = await res.json();
                if (data.success) setTradingPartners(data.data);
            } catch (err) {
                console.error('거래처 목록 조회 오류:', err);
            }
        };

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

        const handleRequestCollect = async () => {
            if (!confirm('홈택스 데이터 수집을 요청하시겠습니까?\n수집에는 시간이 걸릴 수 있습니다.')) return;

            try {
                // 1단계: 바로빌에 홈택스 스크래핑 요청
                const res = await fetch(API.requestCollect, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN
                    },
                    body: JSON.stringify({ type: 'all' })
                });

                const data = await res.json();
                if (data.success) {
                    notify('홈택스 수집 요청 완료. 3초 후 동기화를 시작합니다...', 'success');
                    loadCollectStatus();

                    // 2단계: 3초 대기 후 바로빌 → 로컬 DB 동기화
                    await new Promise(r => setTimeout(r, 3000));

                    const syncRes = await fetch(API.sync, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'X-CSRF-TOKEN': CSRF_TOKEN
                        },
                        body: JSON.stringify({
                            type: activeTab === 'sales' ? 'sales' : 'purchase',
                            startDate: dateFrom.replace(/-/g, ''),
                            endDate: dateTo.replace(/-/g, ''),
                            dateType: 3, // 전송일자 기준 (신규 전송건 누락 방지)
                        })
                    });
                    const syncData = await syncRes.json();
                    if (syncData.success) {
                        notify(syncData.message || '동기화 완료', 'success');
                    }

                    // 3단계: 로컬 DB 데이터 새로고침
                    loadCurrentTabData();
                } else {
                    notify(data.error || '수집 요청 실패', 'error');
                }
            } catch (err) {
                notify('수집 요청 오류: ' + err.message, 'error');
            }
        };

        const handleExport = async () => {
            const invoices = activeTab === 'sales' ? salesData.invoices : purchaseData.invoices;
            if (invoices.length === 0) {
                notify('다운로드할 데이터가 없습니다.', 'warning');
                return;
            }

            try {
                const res = await fetch(API.export, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN
                    },
                    body: JSON.stringify({
                        type: activeTab,
                        invoices: invoices
                    })
                });

                if (res.ok) {
                    const blob = await res.blob();
                    const url = window.URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = `홈택스_${activeTab === 'sales' ? '매출' : '매입'}_${dateFrom.replace(/-/g, '')}_${dateTo.replace(/-/g, '')}.csv`;
                    document.body.appendChild(a);
                    a.click();
                    window.URL.revokeObjectURL(url);
                    a.remove();
                } else {
                    const data = await res.json();
                    notify(data.error || '다운로드 실패', 'error');
                }
            } catch (err) {
                notify('다운로드 오류: ' + err.message, 'error');
            }
        };

        // 서비스 진단
        const handleDiagnose = async () => {
            setShowDiagnoseModal(true);
            setDiagnosing(true);
            setDiagnoseResult(null);

            try {
                const res = await fetch(API.diagnose);
                const data = await res.json();
                if (data.success) {
                    setDiagnoseResult(data.data);
                } else {
                    setDiagnoseResult({ error: data.error || '진단 실패' });
                }
            } catch (err) {
                setDiagnoseResult({ error: '서버 통신 오류: ' + err.message });
            } finally {
                setDiagnosing(false);
            }
        };

        // 홈택스 스크래핑 새로고침
        const handleRefreshScrap = async () => {
            try {
                const res = await fetch(API.refreshScrap, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN
                    }
                });
                const data = await res.json();
                if (data.success) {
                    notify(data.message || '홈택스 데이터 수집이 요청되었습니다.', 'success');
                    // 수집 완료 후 현재 탭 데이터만 새로고침
                    loadCurrentTabData();
                } else {
                    notify(data.error || '수집 요청 실패', 'error');
                }
            } catch (err) {
                notify('수집 요청 오류: ' + err.message, 'error');
            }
        };

        // 수동입력 삭제
        const handleDeleteManual = async (inv) => {
            if (!confirm(`"${inv.invoicerCorpName || inv.invoiceeCorpName}" 세금계산서를 삭제하시겠습니까?`)) return;
            try {
                const url = API.manualDestroy.replace('__ID__', inv.id);
                const res = await fetch(url, {
                    method: 'DELETE',
                    headers: { 'X-CSRF-TOKEN': CSRF_TOKEN }
                });
                const data = await res.json();
                if (data.success) {
                    notify('삭제되었습니다.', 'success');
                    loadCurrentTabData();
                } else {
                    notify(data.error || '삭제 실패', 'error');
                }
            } catch (err) {
                notify('삭제 오류: ' + err.message, 'error');
            }
        };

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

                const res = await fetch(url, {
                    method,
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN
                    },
                    body: JSON.stringify(formData)
                });
                const data = await res.json();
                if (data.success) {
                    notify(data.message, 'success');
                    setShowManualModal(false);
                    loadCurrentTabData();
                } else {
                    notify(data.error || '저장 실패', 'error');
                }
            } catch (err) {
                notify('저장 오류: ' + err.message, 'error');
            }
        };

        // 분개 저장
        const handleJournalSave = async (invoiceId, lines) => {
            try {
                const res = await fetch(API.createJournalEntry, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': CSRF_TOKEN
                    },
                    body: JSON.stringify({ invoice_id: invoiceId, lines })
                });
                const data = await res.json();
                if (data.success) {
                    notify(data.message || '분개가 저장되었습니다.', 'success');
                    setShowJournalModal(false);
                    setJournalInvoice(null);
                    loadCurrentTabData();
                } else {
                    const errorMsg = data.error || '분개 저장 실패';
                    console.error('분개 저장 실패:', data);
                    notify(errorMsg, 'error');
                }
            } catch (err) {
                console.error('분개 저장 오류:', err);
                notify('분개 저장 오류: ' + err.message, 'error');
            }
        };

        // 분개 삭제
        const handleJournalDelete = async (invoiceId) => {
            try {
                const res = await fetch(`${API.deleteJournals}?invoice_id=${invoiceId}`, {
                    method: 'DELETE',
                    headers: {
                        'X-CSRF-TOKEN': CSRF_TOKEN
                    }
                });
                const data = await res.json();
                if (data.success) {
                    notify(data.message || '분개가 삭제되었습니다.', 'success');
                    setShowJournalModal(false);
                    setJournalInvoice(null);
                    loadCurrentTabData();
                } 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);
        };

        // 분기 계산 (1분기: 1-3월, 2분기: 4-6월, 3분기: 7-9월, 4분기: 10-12월)
        const handleQuarter = (quarter) => {
            const now = getKoreanNow();
            const year = now.getFullYear();
            const startMonth = (quarter - 1) * 3;
            const firstDay = new Date(year, startMonth, 1);
            const lastDay = new Date(year, startMonth + 3, 0);
            setDateFrom(formatKoreanDate(firstDay));
            setDateTo(formatKoreanDate(lastDay));
            setSelectedPeriod('q' + quarter);
        };

        // 거래처 필터링
        const filterByCorpName = (invoices) => {
            if (!searchCorpName.trim()) return invoices;
            const keyword = searchCorpName.trim().toLowerCase();
            return invoices.filter(inv => {
                const corpName = (activeTab === 'sales' ? inv.invoiceeCorpName : inv.invoicerCorpName) || '';
                const corpNum = (activeTab === 'sales' ? inv.invoiceeCorpNum : inv.invoicerCorpNum) || '';
                return corpName.toLowerCase().includes(keyword) || corpNum.includes(keyword);
            });
        };

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

        // 과세/면세 합계 계산
        const calculateTaxTypeSummary = (invoices) => {
            let taxableAmount = 0;  // 과세 공급가액
            let exemptAmount = 0;   // 면세 공급가액
            let taxableCount = 0;
            let exemptCount = 0;

            invoices.forEach(inv => {
                const amount = inv.supplyAmount || 0;
                if (inv.taxTypeName === '면세') {
                    exemptAmount += amount;
                    exemptCount++;
                } else {
                    taxableAmount += amount;
                    taxableCount++;
                }
            });

            return { taxableAmount, exemptAmount, taxableCount, exemptCount };
        };

        const currentData = activeTab === 'sales' ? salesData : purchaseData;
        const filteredInvoices = filterByCorpName(currentData.invoices);

        // 매입 과세/면세 합계
        const purchaseTaxSummary = calculateTaxTypeSummary(purchaseData.invoices);
        // 현재 탭 인보이스 합계 (테이블 합계용)
        const currentInvoiceSummary = {
            supplyAmount: filteredInvoices.reduce((sum, inv) => sum + (inv.supplyAmount || 0), 0),
            taxAmount: filteredInvoices.reduce((sum, inv) => sum + (inv.taxAmount || 0), 0),
            totalAmount: filteredInvoices.reduce((sum, inv) => sum + (inv.totalAmount || 0), 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">홈택스에 신고된 세금계산서 매입/매출 내역 조회</p>
                    </div>
                    <div className="flex items-center gap-2">
                        <button
                            onClick={handleDiagnose}
                            className="px-3 py-1.5 bg-stone-100 text-stone-700 rounded-lg text-xs font-medium hover:bg-stone-200 transition-colors flex items-center gap-1"
                        >
                            <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
                            </svg>
                            서비스 진단
                        </button>
                        @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-lg shadow-sm border border-[#dee2e6]">
                    {/* 검색기간 행 */}
                    <div className="flex flex-wrap items-center gap-3 px-5 py-4 border-b border-[#dee2e6]">
                        <label className="text-sm font-medium text-[#495057] w-20 shrink-0">검색기간</label>
                        <select
                            value={dateType}
                            onChange={(e) => setDateType(e.target.value)}
                            className="px-3 py-2 text-sm border border-[#ced4da] rounded bg-white focus:border-[#86b7fe] focus:ring-2 focus:ring-[#86b7fe]/25 outline-none"
                        >
                            <option value="write">작성일자</option>
                            <option value="issue">발급일자</option>
                        </select>
                        <div className="flex items-center gap-1">
                            <input
                                type="date"
                                value={dateFrom}
                                onChange={(e) => { setDateFrom(e.target.value); setSelectedPeriod(null); }}
                                className="px-3 py-2 text-sm border border-[#ced4da] rounded bg-white focus:border-[#86b7fe] focus:ring-2 focus:ring-[#86b7fe]/25 outline-none"
                            />
                            <span className="text-[#6c757d] px-1">~</span>
                            <input
                                type="date"
                                value={dateTo}
                                onChange={(e) => { setDateTo(e.target.value); setSelectedPeriod(null); }}
                                className="px-3 py-2 text-sm border border-[#ced4da] rounded bg-white focus:border-[#86b7fe] focus:ring-2 focus:ring-[#86b7fe]/25 outline-none"
                            />
                        </div>
                        {/* 분기/기/년 버튼 그룹 */}
                        <div className="flex items-center">
                            <button
                                onClick={() => handleQuarter(1)}
                                className={`px-3 py-2 text-xs border border-[#ced4da] transition-colors rounded-l ${selectedPeriod === 'q1' ? 'bg-[#0d6efd] text-white border-[#0d6efd]' : 'bg-white hover:bg-[#e9ecef]'}`}
                            >1분기</button>
                            <button
                                onClick={() => handleQuarter(2)}
                                className={`px-3 py-2 text-xs border-t border-b border-[#ced4da] transition-colors ${selectedPeriod === 'q2' ? 'bg-[#0d6efd] text-white border-[#0d6efd]' : 'bg-white hover:bg-[#e9ecef]'}`}
                            >2분기</button>
                            <button
                                onClick={() => handleQuarter(3)}
                                className={`px-3 py-2 text-xs border-t border-b border-[#ced4da] transition-colors ${selectedPeriod === 'q3' ? 'bg-[#0d6efd] text-white border-[#0d6efd]' : 'bg-white hover:bg-[#e9ecef]'}`}
                            >3분기</button>
                            <button
                                onClick={() => handleQuarter(4)}
                                className={`px-3 py-2 text-xs border border-[#ced4da] rounded-r transition-colors ${selectedPeriod === 'q4' ? 'bg-[#0d6efd] text-white border-[#0d6efd]' : 'bg-white hover:bg-[#e9ecef]'}`}
                            >4분기</button>
                        </div>
                        {/* 조회 버튼 */}
                        <button
                            onClick={loadCurrentTabData}
                            disabled={loading}
                            className="px-4 py-1.5 text-sm bg-emerald-600 text-white rounded-lg hover:bg-emerald-700 transition-colors font-medium disabled:opacity-50 flex items-center gap-2"
                        >
                            {loading ? (
                                <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
                            ) : (
                                <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>
                    {/* 거래처 행 */}
                    <div className="flex flex-wrap items-center gap-3 px-5 py-4 border-b border-[#dee2e6]">
                        <label className="text-sm font-medium text-[#495057] w-20 shrink-0">거래처</label>
                        <input
                            type="text"
                            value={searchCorpName}
                            onChange={(e) => setSearchCorpName(e.target.value)}
                            placeholder="사업자번호 또는 사업자명"
                            className="flex-1 max-w-md px-3 py-2 text-sm border border-[#ced4da] rounded bg-white focus:border-[#86b7fe] focus:ring-2 focus:ring-[#86b7fe]/25 outline-none"
                        />
                        <span className="text-xs text-[#6c757d]">(사업자번호 또는 사업자명)</span>
                    </div>
                    {/* 동기화 상태 */}
                    <div className="flex flex-wrap items-center gap-3 px-5 py-3 border-t border-[#dee2e6]">
                        <label className="text-sm font-medium text-[#495057] w-20 shrink-0">동기화</label>
                        <div className="flex items-center gap-3">
                            {autoSyncing && (
                                <span className="flex items-center gap-2 text-xs text-[#0d6efd]">
                                    <div className="animate-spin rounded-full h-3 w-3 border-2 border-[#0d6efd] border-t-transparent"></div>
                                    바로빌 동기화 중...
                                </span>
                            )}
                            {lastSyncAt[activeTab] && (
                                <span className="text-xs text-[#6c757d]">
                                    마지막 동기화: {lastSyncAt[activeTab]}
                                </span>
                            )}
                        </div>
                    </div>
                    {/* 현재 조회 결과 */}
                    <div className="px-5 py-3 bg-[#f8f9fa] border-t border-[#dee2e6] flex items-center justify-between text-sm">
                        <div className="flex items-center gap-2">
                            <span className="text-[#6c757d]">현재 조회 기간:</span>
                            <span className="font-semibold text-[#6f42c1]">{dateFrom} ~ {dateTo}</span>
                            <span className="text-[#6c757d] ml-2">({dateType === 'write' ? '작성일자' : '발급일자'} 기준)</span>
                        </div>
                        <div className="flex items-center gap-4">
                            <span className="text-[#6c757d]">
                                매출 <span className="font-semibold text-[#198754]">{salesData.summary.count || 0}</span>건
                            </span>
                            <span className="text-[#6c757d]">
                                매입 <span className="font-semibold text-[#dc3545]">{purchaseData.summary.count || 0}</span>건
                            </span>
                        </div>
                    </div>
                </div>

                {/* 수집 상태 안내 */}
                {collectStatus && (
                    <div className={`p-4 rounded-xl ${collectStatus.isCollecting ? 'bg-amber-50 border border-amber-200' : 'bg-stone-50 border border-stone-200'}`}>
                        <div className="flex items-center gap-3">
                            {collectStatus.isCollecting ? (
                                <>
                                    <div className="animate-spin rounded-full h-5 w-5 border-b-2 border-amber-600"></div>
                                    <span className="text-amber-700 font-medium">홈택스 데이터 수집 중...</span>
                                </>
                            ) : (
                                <>
                                    <svg className="w-5 h-5 text-stone-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
                                    </svg>
                                    <span className="text-stone-600">
                                        마지막 수집: 매출 {collectStatus.salesLastCollectDate || '-'} / 매입 {collectStatus.purchaseLastCollectDate || '-'}
                                    </span>
                                    <span className="text-stone-400 mx-1">|</span>
                                    <span className="text-xs text-stone-400">
                                        바로빌 경유 수집 (전일까지 데이터 제공, 당일 발행분은 익일 반영)
                                    </span>
                                </>
                            )}
                        </div>
                    </div>
                )}

                {/* Dashboard */}
                <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4">
                    <StatCard
                        title="매출 공급가액"
                        value={formatCurrency(salesData.summary.totalAmount)}
                        subtext={`${salesData.summary.count || 0}건`}
                        icon={<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"/></svg>}
                        color="green"
                    />
                    <StatCard
                        title="매출 세액"
                        value={formatCurrency(salesData.summary.totalTax)}
                        subtext="부가세 합계"
                        icon={<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 14l6-6m-5.5.5h.01m4.99 5h.01M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16l3.5-2 3.5 2 3.5-2 3.5 2z"/></svg>}
                        color="blue"
                    />
                    <StatCard
                        title="매입 과세 공급가액"
                        value={formatCurrency(purchaseTaxSummary.taxableAmount)}
                        subtext={`${purchaseTaxSummary.taxableCount}건`}
                        icon={<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 17h8m0 0V9m0 8l-8-8-4 4-6-6"/></svg>}
                        color="red"
                    />
                    <StatCard
                        title="매입 면세 공급가액"
                        value={formatCurrency(purchaseTaxSummary.exemptAmount)}
                        subtext={`${purchaseTaxSummary.exemptCount}건`}
                        icon={<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>}
                        color="purple"
                    />
                    <StatCard
                        title="매입 세액"
                        value={formatCurrency(purchaseData.summary.totalTax)}
                        subtext="매입세액 합계"
                        icon={<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 14l6-6m-5.5.5h.01m4.99 5h.01M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16l3.5-2 3.5 2 3.5-2 3.5 2z"/></svg>}
                        color="amber"
                    />
                </div>

                {/* Tab Buttons */}
                <div className="flex gap-3">
                    <TabButton
                        active={activeTab === 'sales'}
                        onClick={() => setActiveTab('sales')}
                        badge={salesData.summary.count || 0}
                    >
                        <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"/>
                        </svg>
                        매출
                    </TabButton>
                    <TabButton
                        active={activeTab === 'purchase'}
                        onClick={() => setActiveTab('purchase')}
                        badge={purchaseData.summary.count || 0}
                    >
                        <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 17h8m0 0V9m0 8l-8-8-4 4-6-6"/>
                        </svg>
                        매입
                    </TabButton>
                    <button
                        onClick={() => {
                            setManualEditData(null);
                            setShowManualModal(true);
                        }}
                        className="ml-auto px-4 py-3 text-sm font-medium rounded-lg bg-violet-600 text-white hover:bg-violet-700 transition-colors shadow-lg shadow-violet-200 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="M12 4v16m8-8H4" />
                        </svg>
                        수동 입력
                    </button>
                </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('-60002') && (
                                    <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>바로빌 사이트에 로그인</li>
                                            <li>홈택스 연동 설정 메뉴 확인</li>
                                            <li>홈택스 인증서 등록 및 연동 설정</li>
                                            <li>부서사용자 ID/비밀번호 설정</li>
                                        </ol>
                                    </div>
                                )}
                                {error.includes('-60004') && (
                                    <div className="mt-3 p-3 bg-white rounded border border-red-200 text-sm">
                                        <p className="font-medium mb-2">해결 방법:</p>
                                        <p className="text-stone-700">홈택스에서 부서사용자 아이디를 생성 후 바로빌에 등록해주세요.</p>
                                    </div>
                                )}
                            </div>
                        </div>
                    </div>
                )}

                {/* Invoice Table */}
                {!error && (
                    <InvoiceTable
                        invoices={filteredInvoices}
                        loading={loading}
                        type={activeTab}
                        onExport={handleExport}
                        onRequestCollect={handleRequestCollect}
                        summary={currentInvoiceSummary}
                        onJournalEntry={(inv) => {
                            setJournalInvoice({...inv, invoiceType: activeTab});
                            setShowJournalModal(true);
                        }}
                        onEditManual={(inv) => {
                            setManualEditData(inv);
                            setShowManualModal(true);
                        }}
                        onDeleteManual={handleDeleteManual}
                    />
                )}

                {/* Summary Card */}
                {!error && !loading && (
                    <div className="bg-gradient-to-r from-purple-50 to-violet-50 rounded-xl p-6 border border-purple-100">
                        <h3 className="text-lg font-bold text-stone-900 mb-4">기간 요약</h3>
                        <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
                            <div>
                                <p className="text-sm text-stone-500 mb-1">매출 합계 (공급가액 + 세액)</p>
                                <p className="text-2xl font-bold text-green-600">{formatCurrency(salesData.summary.totalSum)}</p>
                            </div>
                            <div>
                                <p className="text-sm text-stone-500 mb-1">매입 합계 (공급가액 + 세액)</p>
                                <p className="text-2xl font-bold text-red-600">{formatCurrency(purchaseData.summary.totalSum)}</p>
                            </div>
                            <div>
                                <p className="text-sm text-stone-500 mb-1">예상 부가세 (매출세액 - 매입세액)</p>
                                <p className={`text-2xl font-bold ${
                                    (salesData.summary.totalTax || 0) - (purchaseData.summary.totalTax || 0) >= 0
                                        ? 'text-purple-600'
                                        : 'text-blue-600'
                                }`}>
                                    {formatCurrency((salesData.summary.totalTax || 0) - (purchaseData.summary.totalTax || 0))}
                                </p>
                            </div>
                        </div>
                    </div>
                )}

                {/* 진단 모달 */}
                {showDiagnoseModal && (
                    <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
                        <div className="bg-white rounded-2xl shadow-2xl w-full max-w-2xl mx-4 max-h-[80vh] overflow-hidden">
                            <div className="p-6 border-b border-stone-100 flex items-center justify-between">
                                <h3 className="text-lg font-bold text-stone-900">홈택스 서비스 진단</h3>
                                <button
                                    onClick={() => setShowDiagnoseModal(false)}
                                    className="p-2 hover:bg-stone-100 rounded-lg transition-colors"
                                >
                                    <svg className="w-5 h-5 text-stone-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
                                    </svg>
                                </button>
                            </div>
                            <div className="p-6 overflow-y-auto max-h-[60vh]">
                                {diagnosing ? (
                                    <div className="flex items-center justify-center py-10">
                                        <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-purple-600"></div>
                                        <span className="ml-3 text-stone-500">서비스 진단 중...</span>
                                    </div>
                                ) : diagnoseResult?.error ? (
                                    <div className="bg-red-50 text-red-600 p-4 rounded-xl">
                                        {diagnoseResult.error}
                                    </div>
                                ) : diagnoseResult && (
                                    <div className="space-y-6">
                                        {/* 설정 정보 */}
                                        <div>
                                            <h4 className="text-sm font-semibold text-stone-700 mb-3">API 설정</h4>
                                            <div className="bg-stone-50 rounded-xl p-4 space-y-2 text-sm">
                                                <div className="flex justify-between">
                                                    <span className="text-stone-500">CERTKEY</span>
                                                    <span className="font-mono text-stone-700">{diagnoseResult.config?.certKey}</span>
                                                </div>
                                                <div className="flex justify-between">
                                                    <span className="text-stone-500">파트너사업자번호</span>
                                                    <span className="font-mono text-stone-700">{diagnoseResult.config?.corpNum}</span>
                                                </div>
                                                <div className="flex justify-between">
                                                    <span className="text-stone-500">테스트모드</span>
                                                    <span className={diagnoseResult.config?.isTestMode ? 'text-amber-600' : 'text-green-600'}>
                                                        {diagnoseResult.config?.isTestMode ? '예' : '아니오'}
                                                    </span>
                                                </div>
                                                <div className="flex justify-between">
                                                    <span className="text-stone-500">API URL</span>
                                                    <span className="font-mono text-xs text-stone-600">{diagnoseResult.config?.baseUrl}</span>
                                                </div>
                                            </div>
                                        </div>

                                        {/* 회원사 정보 */}
                                        <div>
                                            <h4 className="text-sm font-semibold text-stone-700 mb-3">회원사 정보</h4>
                                            <div className="bg-stone-50 rounded-xl p-4 space-y-2 text-sm">
                                                <div className="flex justify-between">
                                                    <span className="text-stone-500">바로빌 ID</span>
                                                    <span className="font-mono text-stone-700">{diagnoseResult.member?.userId || '미설정'}</span>
                                                </div>
                                                <div className="flex justify-between">
                                                    <span className="text-stone-500">사업자번호</span>
                                                    <span className="font-mono text-stone-700">{diagnoseResult.member?.bizNo || '미설정'}</span>
                                                </div>
                                                <div className="flex justify-between">
                                                    <span className="text-stone-500">상호</span>
                                                    <span className="text-stone-700">{diagnoseResult.member?.corpName || '미설정'}</span>
                                                </div>
                                            </div>
                                        </div>

                                        {/* API 테스트 결과 */}
                                        <div>
                                            <h4 className="text-sm font-semibold text-stone-700 mb-3">API 테스트 결과</h4>
                                            <div className="space-y-3">
                                                {Object.entries(diagnoseResult.tests || {}).map(([key, test]) => (
                                                    <div key={key} className={`rounded-xl p-4 ${test.success ? 'bg-green-50' : 'bg-red-50'}`}>
                                                        <div className="flex items-start justify-between">
                                                            <div>
                                                                <p className="font-medium text-stone-700">{test.method}</p>
                                                                <p className={`text-sm mt-1 ${test.success ? 'text-green-600' : 'text-red-600'}`}>
                                                                    {test.result}
                                                                </p>
                                                            </div>
                                                            <span className={`px-2 py-1 rounded-full text-xs font-medium ${
                                                                test.success ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'
                                                            }`}>
                                                                {test.success ? '성공' : '실패'}
                                                            </span>
                                                        </div>
                                                    </div>
                                                ))}
                                            </div>
                                        </div>

                                        {/* 해결 방법 안내 */}
                                        <div className="bg-amber-50 rounded-xl p-4 text-sm">
                                            <p className="font-medium text-amber-800 mb-2">💡 문제 해결 안내</p>
                                            <ul className="text-amber-700 space-y-1">
                                                <li>• API 권한 오류 시: 바로빌 사이트에서 홈택스 연동 서비스 신청 필요</li>
                                                <li>• 홈택스 연동 미등록 시: 부서사용자 또는 인증서 방식으로 홈택스 연동 등록 필요</li>
                                                <li>• 데이터 미조회 시: 바로빌에서 발행한 세금계산서만 API로 조회 가능</li>
                                            </ul>
                                        </div>
                                    </div>
                                )}
                            </div>
                            <div className="p-4 border-t border-stone-100 flex justify-end gap-3">
                                <button
                                    onClick={handleRefreshScrap}
                                    className="px-4 py-2 bg-purple-600 text-white rounded-lg text-sm font-medium hover:bg-purple-700 transition-colors"
                                >
                                    홈택스 수집 요청
                                </button>
                                <button
                                    onClick={() => setShowDiagnoseModal(false)}
                                    className="px-4 py-2 bg-stone-100 text-stone-700 rounded-lg text-sm font-medium hover:bg-stone-200 transition-colors"
                                >
                                    닫기
                                </button>
                            </div>
                        </div>
                    </div>
                )}

                {/* 수동입력 모달 */}
                {showManualModal && (
                    <ManualInputModal
                        isOpen={showManualModal}
                        onClose={() => setShowManualModal(false)}
                        onSave={handleManualSave}
                        editData={manualEditData}
                        invoiceType={activeTab}
                        tradingPartners={tradingPartners}
                        onAddPartner={() => setShowAddPartnerModal(true)}
                    />
                )}

                {/* 거래처 추가 모달 */}
                <HometaxAddTradingPartnerModal
                    isOpen={showAddPartnerModal}
                    onClose={() => setShowAddPartnerModal(false)}
                    onSaved={(newPartner) => {
                        setTradingPartners(prev => [...prev, newPartner]);
                        setShowAddPartnerModal(false);
                    }}
                />

                {/* 분개 모달 */}
                {showJournalModal && journalInvoice && (
                    <JournalEntryModal
                        isOpen={showJournalModal}
                        onClose={() => { setShowJournalModal(false); setJournalInvoice(null); }}
                        onSave={handleJournalSave}
                        onDelete={handleJournalDelete}
                        invoice={journalInvoice}
                        accountCodes={accountCodes}
                    />
                )}
            </div>
        );
    };

    // ============================================
    // HometaxTradingPartnerSelect - 거래처 드롭다운
    // ============================================
    const HometaxTradingPartnerSelect = ({ value, valueName, onChange, tradingPartners, onAddPartner }) => {
        const [isOpen, setIsOpen] = useState(false);
        const [search, setSearch] = useState('');
        const [highlightIndex, setHighlightIndex] = useState(-1);
        const containerRef = useRef(null);
        const listRef = useRef(null);

        const displayText = valueName || '';

        const filteredPartners = tradingPartners.filter(p => {
            if (!search) return true;
            const s = search.toLowerCase();
            return p.name.toLowerCase().includes(s) || (p.biz_no && p.biz_no.includes(search));
        });

        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 = (partner) => {
            onChange(partner.id, partner.name, partner.biz_no || '', partner);
            setIsOpen(false); setSearch(''); setHighlightIndex(-1);
        };
        const handleClear = (e) => { e.stopPropagation(); onChange(null, '', ''); setSearch(''); };

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

        return (
            <div ref={containerRef} className="relative">
                <div onClick={() => setIsOpen(!isOpen)}
                    className={`w-full px-3 py-2 text-sm border rounded-lg cursor-pointer flex items-center justify-between gap-1 ${isOpen ? 'border-violet-500 ring-2 ring-violet-500' : 'border-stone-300'} 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.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" /></svg>
                        </button>}
                        <svg className={`w-3.5 h-3.5 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-[60] mt-1 w-72 bg-white border border-stone-200 rounded-lg shadow-lg">
                        <div className="p-2 border-b border-stone-100">
                            <input type="text" value={search} onChange={(e) => setSearch(e.target.value)} onKeyDown={handleKeyDown}
                                placeholder="거래처명 또는 사업자번호 검색..." className="w-full px-2.5 py-1.5 text-sm border border-stone-200 rounded-lg focus:ring-1 focus:ring-violet-500 outline-none" autoFocus />
                        </div>
                        <div className="border-b border-stone-100">
                            <button onClick={(e) => { e.stopPropagation(); setIsOpen(false); onAddPartner && onAddPartner(); }}
                                className="w-full px-3 py-2 text-xs text-violet-600 hover:bg-violet-50 font-medium flex items-center gap-1 justify-center transition-colors">
                                <svg className="w-3.5 h-3.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 ref={listRef} className="max-h-48 overflow-y-auto">
                            {filteredPartners.length === 0 ? (
                                <div className="px-3 py-2 text-xs text-stone-400 text-center">검색 결과 없음</div>
                            ) : filteredPartners.slice(0, 50).map((p, index) => (
                                <div key={p.id} onClick={() => handleSelect(p)}
                                    className={`px-3 py-1.5 text-sm cursor-pointer ${index === highlightIndex ? 'bg-violet-600 text-white font-semibold' : value === p.id ? 'bg-violet-100 text-violet-700' : 'text-stone-700 hover:bg-violet-50'}`}>
                                    <span className="font-medium">{p.name}</span>
                                    {p.biz_no && <span className={`ml-1 text-xs ${index === highlightIndex ? 'text-violet-100' : 'text-stone-400'}`}>({p.biz_no})</span>}
                                </div>
                            ))}
                            {filteredPartners.length > 50 && <div className="px-3 py-1 text-xs text-stone-400 text-center border-t">+{filteredPartners.length - 50}개 더 있음</div>}
                        </div>
                    </div>
                )}
            </div>
        );
    };

    // ============================================
    // HometaxAddTradingPartnerModal - 거래처 추가 모달
    // ============================================
    const HometaxAddTradingPartnerModal = ({ isOpen, onClose, onSaved }) => {
        const [saving, setSaving] = useState(false);
        const [form, setForm] = useState({
            name: '', type: 'vendor', category: '기타', bizNo: '', contact: '', manager: '', memo: '',
        });

        const categories = ['기타', '제조업', '도소매업', '서비스업', '건설업', 'IT', '금융', '물류'];

        const handleSave = async () => {
            if (!form.name.trim()) { notify('거래처명을 입력하세요.', 'warning'); return; }
            setSaving(true);
            try {
                const res = await fetch('/finance/partners/store', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': CSRF_TOKEN },
                    body: JSON.stringify(form),
                });
                const data = await res.json();
                if (data.success) {
                    onSaved({ id: data.data.id, name: data.data.name, biz_no: data.data.bizNo, type: data.data.type });
                    setForm({ name: '', type: 'vendor', category: '기타', bizNo: '', contact: '', manager: '', memo: '' });
                    onClose();
                    notify('거래처가 추가되었습니다.', 'success');
                } else {
                    notify(data.message || '저장에 실패했습니다.', 'error');
                }
            } catch (err) {
                notify('저장 중 오류가 발생했습니다.', 'error');
            } finally {
                setSaving(false);
            }
        };

        if (!isOpen) return null;

        return (
            <div className="fixed inset-0 z-[100] flex items-center justify-center">
                <div className="absolute inset-0 bg-black/40" />
                <div className="relative bg-white rounded-xl shadow-2xl w-full max-w-md mx-4">
                    <div className="flex items-center justify-between px-5 py-4 border-b border-stone-200">
                        <h3 className="text-base font-bold text-stone-800">거래처 추가</h3>
                        <button onClick={onClose} className="p-1 text-stone-400 hover:text-stone-600 rounded">
                            <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" /></svg>
                        </button>
                    </div>
                    <div className="px-5 py-4 space-y-3">
                        <div>
                            <label className="block text-xs font-medium text-stone-500 mb-1">거래처명 <span className="text-red-500">*</span></label>
                            <input type="text" value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })}
                                placeholder="거래처명을 입력하세요"
                                className="w-full px-3 py-2 text-sm border border-stone-200 rounded-lg focus:ring-2 focus:ring-violet-500 outline-none" autoFocus />
                        </div>
                        <div className="grid grid-cols-2 gap-3">
                            <div>
                                <label className="block text-xs font-medium text-stone-500 mb-1">구분</label>
                                <select value={form.type} onChange={(e) => setForm({ ...form, type: e.target.value })}
                                    className="w-full px-3 py-2 text-sm border border-stone-200 rounded-lg focus:ring-2 focus:ring-violet-500 outline-none">
                                    <option value="vendor">거래처</option>
                                    <option value="freelancer">프리랜서</option>
                                </select>
                            </div>
                            <div>
                                <label className="block text-xs font-medium text-stone-500 mb-1">업종</label>
                                <select value={form.category} onChange={(e) => setForm({ ...form, category: e.target.value })}
                                    className="w-full px-3 py-2 text-sm border border-stone-200 rounded-lg focus:ring-2 focus:ring-violet-500 outline-none">
                                    {categories.map(c => <option key={c} value={c}>{c}</option>)}
                                </select>
                            </div>
                        </div>
                        <div>
                            <label className="block text-xs font-medium text-stone-500 mb-1">사업자번호</label>
                            <input type="text" value={form.bizNo} onChange={(e) => setForm({ ...form, bizNo: e.target.value })}
                                placeholder="000-00-00000"
                                className="w-full px-3 py-2 text-sm border border-stone-200 rounded-lg focus:ring-2 focus:ring-violet-500 outline-none" />
                        </div>
                        <div className="grid grid-cols-2 gap-3">
                            <div>
                                <label className="block text-xs font-medium text-stone-500 mb-1">연락처</label>
                                <input type="text" value={form.contact} onChange={(e) => setForm({ ...form, contact: e.target.value })}
                                    placeholder="전화번호"
                                    className="w-full px-3 py-2 text-sm border border-stone-200 rounded-lg focus:ring-2 focus:ring-violet-500 outline-none" />
                            </div>
                            <div>
                                <label className="block text-xs font-medium text-stone-500 mb-1">담당자</label>
                                <input type="text" value={form.manager} onChange={(e) => setForm({ ...form, manager: e.target.value })}
                                    placeholder="담당자명"
                                    className="w-full px-3 py-2 text-sm border border-stone-200 rounded-lg focus:ring-2 focus:ring-violet-500 outline-none" />
                            </div>
                        </div>
                        <div>
                            <label className="block text-xs font-medium text-stone-500 mb-1">메모</label>
                            <input type="text" value={form.memo} onChange={(e) => setForm({ ...form, memo: e.target.value })}
                                placeholder="메모"
                                className="w-full px-3 py-2 text-sm border border-stone-200 rounded-lg focus:ring-2 focus:ring-violet-500 outline-none" />
                        </div>
                    </div>
                    <div className="flex justify-end gap-2 px-5 py-4 border-t border-stone-200">
                        <button onClick={onClose} className="px-4 py-2 text-sm text-stone-600 bg-stone-100 rounded-lg hover:bg-stone-200 transition-colors">취소</button>
                        <button onClick={handleSave} disabled={saving}
                            className="px-4 py-2 text-sm font-medium text-white bg-violet-600 rounded-lg hover:bg-violet-700 transition-colors disabled:opacity-50">
                            {saving ? '저장 중...' : '저장'}
                        </button>
                    </div>
                </div>
            </div>
        );
    };

    // ============================================
    // ManualInputModal - 수동입력 모달
    // ============================================
    const ManualInputModal = ({ isOpen, onClose, onSave, editData, invoiceType, tradingPartners, onAddPartner }) => {
        const [form, setForm] = useState({
            invoice_type: editData?.invoiceType || editData?.invoice_type || invoiceType || 'sales',
            write_date: editData?.writeDateFormatted || editData?.write_date || formatKoreanDate(getKoreanNow()),
            invoicer_corp_name: editData?.invoicerCorpName || editData?.invoicer_corp_name || '',
            invoicer_corp_num: editData?.invoicerCorpNum || editData?.invoicer_corp_num || '',
            invoicer_ceo_name: editData?.invoicer_ceo_name || '',
            invoicer_branch_num: editData?.invoicer_branch_num || '',
            invoicer_address: editData?.invoicer_address || '',
            invoicer_biz_type: editData?.invoicer_biz_type || '',
            invoicer_biz_class: editData?.invoicer_biz_class || '',
            invoicer_email: editData?.invoicer_email || '',
            invoicer_email2: editData?.invoicer_email2 || '',
            invoicee_corp_name: editData?.invoiceeCorpName || editData?.invoicee_corp_name || '',
            invoicee_corp_num: editData?.invoiceeCorpNum || editData?.invoicee_corp_num || '',
            invoicee_ceo_name: editData?.invoicee_ceo_name || '',
            invoicee_branch_num: editData?.invoicee_branch_num || '',
            invoicee_address: editData?.invoicee_address || '',
            invoicee_biz_type: editData?.invoicee_biz_type || '',
            invoicee_biz_class: editData?.invoicee_biz_class || '',
            invoicee_email: editData?.invoicee_email || '',
            invoicee_email2: editData?.invoicee_email2 || '',
            supply_amount: editData?.supplyAmount || editData?.supply_amount || '',
            tax_amount: editData?.taxAmount || editData?.tax_amount || '',
            item_name: editData?.itemName || editData?.item_name || '',
            remark: editData?.remark || '',
            tax_type: editData?.taxType || editData?.tax_type || 1,
            purpose_type: editData?.purposeType || editData?.purpose_type || 1,
        });
        const [showCardPicker, setShowCardPicker] = useState(false);
        const [saving, setSaving] = useState(false);

        // 거래처 드롭다운 상태
        const [selectedPartnerId, setSelectedPartnerId] = useState(() => {
            // 수정 모드일 때 기존 거래처명으로 매칭 시도
            if (editData && tradingPartners) {
                const isSalesEdit = (editData.invoiceType || editData.invoice_type || invoiceType) === 'sales';
                const corpName = isSalesEdit
                    ? (editData.invoiceeCorpName || editData.invoicee_corp_name || '')
                    : (editData.invoicerCorpName || editData.invoicer_corp_name || '');
                const matched = tradingPartners.find(p => p.name === corpName);
                return matched ? matched.id : null;
            }
            return null;
        });
        const [selectedPartnerName, setSelectedPartnerName] = useState(() => {
            if (editData) {
                const isSalesEdit = (editData.invoiceType || editData.invoice_type || invoiceType) === 'sales';
                return isSalesEdit
                    ? (editData.invoiceeCorpName || editData.invoicee_corp_name || '')
                    : (editData.invoicerCorpName || editData.invoicer_corp_name || '');
            }
            return '';
        });

        const handleChange = (field, value) => {
            setForm(prev => ({ ...prev, [field]: value }));
            // 매출/매입 전환 시 거래처 선택 초기화
            if (field === 'invoice_type') {
                setSelectedPartnerId(null);
                setSelectedPartnerName('');
            }
        };

        const handlePartnerSelect = (partnerId, partnerName, bizNo, partner) => {
            setSelectedPartnerId(partnerId);
            setSelectedPartnerName(partnerName);
            const prefix = form.invoice_type === 'sales' ? 'invoicee' : 'invoicer';
            setForm(prev => ({
                ...prev,
                [`${prefix}_corp_name`]: partnerName || '',
                [`${prefix}_corp_num`]: bizNo || prev[`${prefix}_corp_num`],
                [`${prefix}_ceo_name`]: partner?.ceo || '',
                [`${prefix}_address`]: partner?.address || '',
                [`${prefix}_biz_type`]: partner?.type || '',
                [`${prefix}_biz_class`]: partner?.category || '',
                [`${prefix}_email`]: partner?.email || '',
            }));
        };

        // 거래처 검색 팝업 상태
        const [showPartnerSearch, setShowPartnerSearch] = useState(false);
        const [partnerSearchQuery, setPartnerSearchQuery] = useState('');
        const [partnerSearchResults, setPartnerSearchResults] = useState([]);
        const [partnerSearchLoading, setPartnerSearchLoading] = useState(false);
        const partnerSearchRef = useRef(null);
        const partnerSearchTimerRef = useRef(null);
        const partnerSearchInputRef = useRef(null);
        const partnerSearchBtnRef = useRef(null);

        // 검색 팝업 열기/닫기
        const openPartnerSearch = () => {
            setShowPartnerSearch(true);
            setPartnerSearchQuery('');
            setPartnerSearchResults(tradingPartners || []);
        };
        const closePartnerSearch = () => {
            setShowPartnerSearch(false);
            setPartnerSearchQuery('');
            setPartnerSearchResults([]);
        };

        // 검색 팝업 위치 계산 + 포커스 + 외부 클릭
        useEffect(() => {
            if (!showPartnerSearch) return;
            // 위치 계산
            const positionPopup = () => {
                if (!partnerSearchBtnRef.current || !partnerSearchRef.current) return;
                const btnRect = partnerSearchBtnRef.current.getBoundingClientRect();
                const popup = partnerSearchRef.current;
                const popupW = 220, popupMaxH = 360, gap = 6;
                // 가로: 버튼 왼쪽 기준 정렬
                let left = btnRect.left;
                if (left + popupW > window.innerWidth - 8) left = window.innerWidth - popupW - 8;
                if (left < 8) left = 8;
                popup.style.left = left + 'px';
                popup.style.width = popupW + 'px';
                // 세로: 아래 공간 우선, 부족하면 위로
                const spaceBelow = window.innerHeight - btnRect.bottom - gap;
                const spaceAbove = btnRect.top - gap;
                if (spaceBelow >= popupMaxH || spaceBelow >= spaceAbove) {
                    popup.style.top = (btnRect.bottom + gap) + 'px';
                    popup.style.bottom = 'auto';
                } else {
                    popup.style.top = 'auto';
                    popup.style.bottom = (window.innerHeight - btnRect.top + gap) + 'px';
                }
            };
            requestAnimationFrame(() => {
                positionPopup();
                partnerSearchInputRef.current?.focus();
            });
            // 외부 클릭
            const handleClickOutside = (e) => {
                if (partnerSearchRef.current && !partnerSearchRef.current.contains(e.target)
                    && partnerSearchBtnRef.current && !partnerSearchBtnRef.current.contains(e.target)) {
                    closePartnerSearch();
                }
            };
            document.addEventListener('mousedown', handleClickOutside);
            return () => document.removeEventListener('mousedown', handleClickOutside);
        }, [showPartnerSearch]);

        // 검색어 변경 시 로컬 필터 + API 디바운스
        const handlePartnerSearchChange = (query) => {
            setPartnerSearchQuery(query);
            const q = query.trim().toLowerCase();
            // 로컬 필터
            const localResults = (tradingPartners || []).filter(p => {
                if (!q) return true;
                return p.name.toLowerCase().includes(q)
                    || (p.biz_no && p.biz_no.includes(q))
                    || (p.ceo && p.ceo.toLowerCase().includes(q));
            });
            setPartnerSearchResults(localResults);
            // 디바운스 API 검색 (검색어 2글자 이상일 때)
            if (partnerSearchTimerRef.current) clearTimeout(partnerSearchTimerRef.current);
            if (q.length >= 2) {
                partnerSearchTimerRef.current = setTimeout(async () => {
                    setPartnerSearchLoading(true);
                    try {
                        const res = await fetch(`/finance/journal-entries/trading-partners?search=${encodeURIComponent(q)}`);
                        const data = await res.json();
                        if (data.success) {
                            // 로컬 결과와 API 결과 병합 (중복 제거)
                            const localIds = new Set(localResults.map(p => p.id));
                            const apiOnly = data.data.filter(p => !localIds.has(p.id));
                            setPartnerSearchResults([...localResults, ...apiOnly]);
                        }
                    } catch (err) { /* 무시 */ }
                    finally { setPartnerSearchLoading(false); }
                }, 300);
            }
        };

        // 검색 결과에서 거래처 선택
        const handlePartnerSearchSelect = (partner) => {
            handlePartnerSelect(partner.id, partner.name, partner.biz_no, partner);
            closePartnerSearch();
        };

        const totalAmount = (parseFloat(form.supply_amount) || 0) + (parseFloat(form.tax_amount) || 0);

        const handleSubmit = async () => {
            if (!form.write_date || !form.supply_amount) {
                notify('작성일자와 공급가액은 필수입니다.', 'warning');
                return;
            }
            // 매출이면 invoicee(공급받는자), 매입이면 invoicer(공급자) 필수
            if (form.invoice_type === 'sales' && !form.invoicee_corp_name) {
                notify('공급받는자(거래처)명을 입력해주세요.', 'warning');
                return;
            }
            if (form.invoice_type === 'purchase' && !form.invoicer_corp_name) {
                notify('공급자(거래처)명을 입력해주세요.', 'warning');
                return;
            }
            setSaving(true);
            const submitData = { ...form };
            if (editData?.id) submitData.id = editData.id;
            await onSave(submitData);
            setSaving(false);
        };

        const handleCardSelect = (card) => {
            setForm(prev => ({
                ...prev,
                supply_amount: card.supplyAmount || (card.approvalAmount - (card.tax || 0)),
                tax_amount: card.tax || 0,
                invoicer_corp_name: card.merchantName || prev.invoicer_corp_name,
                invoicer_corp_num: card.merchantBizNum || prev.invoicer_corp_num,
                write_date: card.useDate || prev.write_date,
                remark: `카드승인 ${card.approvalNum || ''}`.trim(),
            }));
            // 카드내역 선택 시 거래처 드롭다운도 동기화
            if (card.merchantName) {
                setSelectedPartnerName(card.merchantName);
                const matched = tradingPartners.find(p => p.name === card.merchantName);
                setSelectedPartnerId(matched ? matched.id : null);
            }
            setShowCardPicker(false);
        };

        const isSales = form.invoice_type === 'sales';

        return (
            <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
                <div className="bg-white rounded-2xl shadow-2xl w-full max-w-2xl mx-4 max-h-[90vh] overflow-hidden">
                    <div className="p-6 border-b border-stone-100 flex items-center justify-between">
                        <h3 className="text-lg font-bold text-stone-900">
                            {editData ? '세금계산서 수정' : '세금계산서 수동 입력'}
                        </h3>
                        <button onClick={onClose} className="p-2 hover:bg-stone-100 rounded-lg transition-colors">
                            <svg className="w-5 h-5 text-stone-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
                            </svg>
                        </button>
                    </div>
                    <div className="p-6 overflow-y-auto max-h-[65vh] space-y-4">
                        {/* 매출/매입 구분 + 작성일자 */}
                        <div className="grid grid-cols-2 gap-4">
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">구분 *</label>
                                <select
                                    value={form.invoice_type}
                                    onChange={(e) => handleChange('invoice_type', e.target.value)}
                                    className="w-full px-3 py-2 border border-stone-300 rounded-lg text-sm focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                >
                                    <option value="sales">매출</option>
                                    <option value="purchase">매입</option>
                                </select>
                            </div>
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">작성일자 *</label>
                                <input
                                    type="date"
                                    value={form.write_date}
                                    onChange={(e) => handleChange('write_date', e.target.value)}
                                    className="w-full px-3 py-2 border border-stone-300 rounded-lg text-sm focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                />
                            </div>
                        </div>

                        {/* 거래처 정보 */}
                        {(() => {
                            const prefix = isSales ? 'invoicee' : 'invoicer';
                            const label = isSales ? '공급받는자' : '공급자';
                            return (
                            <div className="bg-stone-50 rounded-xl p-4 space-y-3">
                                <div className="flex items-center justify-between mb-2">
                                    <h4 className="text-sm font-semibold text-stone-700">{label} 정보</h4>
                                    {!editData && form.invoice_type === 'purchase' && (
                                        <button
                                            onClick={() => setShowCardPicker(true)}
                                            className="px-3 py-1.5 bg-violet-100 text-violet-700 rounded-lg text-xs font-medium hover:bg-violet-200 transition-colors flex items-center gap-1"
                                        >
                                            <svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />
                                            </svg>
                                            카드내역 불러오기
                                        </button>
                                    )}
                                </div>
                                {/* 등록번호 + 종사업장번호 */}
                                <div className="grid grid-cols-2 gap-3">
                                    <div>
                                        <label className="block text-xs text-stone-500 mb-1">등록번호 (사업자번호)</label>
                                        <div className="flex gap-1.5">
                                            <input
                                                type="text"
                                                value={form[`${prefix}_corp_num`]}
                                                onChange={(e) => handleChange(`${prefix}_corp_num`, e.target.value)}
                                                className="flex-1 px-3 py-2 border border-stone-300 rounded-lg text-sm focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                                placeholder="000-00-00000"
                                            />
                                            <button
                                                ref={partnerSearchBtnRef}
                                                type="button"
                                                onClick={openPartnerSearch}
                                                className="px-2.5 py-2 bg-violet-100 text-violet-700 rounded-lg hover:bg-violet-200 transition-colors shrink-0"
                                                title="거래처 검색"
                                            >
                                                <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>
                                    </div>
                                    <div>
                                        <label className="block text-xs text-stone-500 mb-1">종사업장번호</label>
                                        <input
                                            type="text"
                                            value={form[`${prefix}_branch_num`]}
                                            onChange={(e) => handleChange(`${prefix}_branch_num`, e.target.value)}
                                            className="w-full px-3 py-2 border border-stone-300 rounded-lg text-sm focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                            placeholder=""
                                        />
                                    </div>
                                </div>
                                {/* 상호 + 성명 */}
                                <div className="grid grid-cols-2 gap-3">
                                    <div>
                                        <label className="block text-xs text-stone-500 mb-1">상호 ({label}명) *</label>
                                        <HometaxTradingPartnerSelect
                                            value={selectedPartnerId}
                                            valueName={form[`${prefix}_corp_name`]}
                                            onChange={handlePartnerSelect}
                                            tradingPartners={tradingPartners || []}
                                            onAddPartner={onAddPartner}
                                        />
                                    </div>
                                    <div>
                                        <label className="block text-xs text-stone-500 mb-1">성명 (대표자)</label>
                                        <input
                                            type="text"
                                            value={form[`${prefix}_ceo_name`]}
                                            onChange={(e) => handleChange(`${prefix}_ceo_name`, e.target.value)}
                                            className="w-full px-3 py-2 border border-stone-300 rounded-lg text-sm focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                            placeholder="대표자명"
                                        />
                                    </div>
                                </div>
                                {/* 사업장 주소 */}
                                <div>
                                    <label className="block text-xs text-stone-500 mb-1">사업장 주소</label>
                                    <input
                                        type="text"
                                        value={form[`${prefix}_address`]}
                                        onChange={(e) => handleChange(`${prefix}_address`, e.target.value)}
                                        className="w-full px-3 py-2 border border-stone-300 rounded-lg text-sm focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                        placeholder="사업장 주소"
                                    />
                                </div>
                                {/* 업태 + 종목 */}
                                <div className="grid grid-cols-2 gap-3">
                                    <div>
                                        <label className="block text-xs text-stone-500 mb-1">업태</label>
                                        <input
                                            type="text"
                                            value={form[`${prefix}_biz_type`]}
                                            onChange={(e) => handleChange(`${prefix}_biz_type`, e.target.value)}
                                            className="w-full px-3 py-2 border border-stone-300 rounded-lg text-sm focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                            placeholder="업태"
                                        />
                                    </div>
                                    <div>
                                        <label className="block text-xs text-stone-500 mb-1">종목</label>
                                        <input
                                            type="text"
                                            value={form[`${prefix}_biz_class`]}
                                            onChange={(e) => handleChange(`${prefix}_biz_class`, e.target.value)}
                                            className="w-full px-3 py-2 border border-stone-300 rounded-lg text-sm focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                            placeholder="종목"
                                        />
                                    </div>
                                </div>
                                {/* 이메일 */}
                                <div className="grid grid-cols-2 gap-3">
                                    <div>
                                        <label className="block text-xs text-stone-500 mb-1">이메일</label>
                                        <input
                                            type="email"
                                            value={form[`${prefix}_email`]}
                                            onChange={(e) => handleChange(`${prefix}_email`, e.target.value)}
                                            className="w-full px-3 py-2 border border-stone-300 rounded-lg text-sm focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                            placeholder="이메일"
                                        />
                                    </div>
                                    <div>
                                        <label className="block text-xs text-stone-500 mb-1">이메일 2</label>
                                        <input
                                            type="email"
                                            value={form[`${prefix}_email2`]}
                                            onChange={(e) => handleChange(`${prefix}_email2`, e.target.value)}
                                            className="w-full px-3 py-2 border border-stone-300 rounded-lg text-sm focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                            placeholder="이메일 2"
                                        />
                                    </div>
                                </div>
                            </div>
                            );
                        })()}

                        {/* 금액 */}
                        <div className="grid grid-cols-3 gap-4">
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">공급가액 *</label>
                                <input
                                    type="number"
                                    value={form.supply_amount}
                                    onChange={(e) => handleChange('supply_amount', e.target.value)}
                                    className="w-full px-3 py-2 border border-stone-300 rounded-lg text-sm text-right focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                    placeholder="0"
                                />
                            </div>
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">세액</label>
                                <input
                                    type="number"
                                    value={form.tax_amount}
                                    onChange={(e) => handleChange('tax_amount', e.target.value)}
                                    className="w-full px-3 py-2 border border-stone-300 rounded-lg text-sm text-right focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                    placeholder="0"
                                />
                            </div>
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">합계</label>
                                <div className="px-3 py-2 bg-stone-100 border border-stone-200 rounded-lg text-sm text-right font-bold text-blue-600">
                                    {new Intl.NumberFormat('ko-KR').format(totalAmount)}
                                </div>
                            </div>
                        </div>

                        {/* 품목 + 과세유형 */}
                        <div className="grid grid-cols-2 gap-4">
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">품목</label>
                                <input
                                    type="text"
                                    value={form.item_name}
                                    onChange={(e) => handleChange('item_name', e.target.value)}
                                    className="w-full px-3 py-2 border border-stone-300 rounded-lg text-sm focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                    placeholder="품목명"
                                />
                            </div>
                            <div>
                                <label className="block text-sm font-medium text-stone-700 mb-1">과세유형</label>
                                <select
                                    value={form.tax_type}
                                    onChange={(e) => handleChange('tax_type', parseInt(e.target.value))}
                                    className="w-full px-3 py-2 border border-stone-300 rounded-lg text-sm focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                >
                                    <option value={1}>과세</option>
                                    <option value={2}>영세</option>
                                    <option value={3}>면세</option>
                                </select>
                            </div>
                        </div>

                        {/* 비고 */}
                        <div>
                            <label className="block text-sm font-medium text-stone-700 mb-1">비고</label>
                            <input
                                type="text"
                                value={form.remark}
                                onChange={(e) => handleChange('remark', e.target.value)}
                                className="w-full px-3 py-2 border border-stone-300 rounded-lg text-sm focus:ring-2 focus:ring-violet-500 focus:border-violet-500 outline-none"
                                placeholder="메모"
                            />
                        </div>
                    </div>
                    <div className="p-4 border-t border-stone-100 flex justify-end gap-3">
                        <button onClick={onClose} className="px-4 py-2 bg-stone-100 text-stone-700 rounded-lg text-sm font-medium hover:bg-stone-200 transition-colors">
                            취소
                        </button>
                        <button
                            onClick={handleSubmit}
                            disabled={saving}
                            className="px-6 py-2 bg-violet-600 text-white rounded-lg text-sm font-medium hover:bg-violet-700 transition-colors disabled:opacity-50 flex items-center gap-2"
                        >
                            {saving && <div className="animate-spin rounded-full h-4 w-4 border-2 border-white border-t-transparent"></div>}
                            {editData ? '수정' : '저장'}
                        </button>
                    </div>
                </div>

                {/* 카드내역 피커 (중첩 모달) */}
                {showCardPicker && (
                    <CardTransactionPicker
                        onSelect={handleCardSelect}
                        onClose={() => setShowCardPicker(false)}
                    />
                )}

                {/* 거래처 검색 팝업 (Portal → body에 렌더링) */}
                {showPartnerSearch && ReactDOM.createPortal(
                    <div ref={partnerSearchRef} className="fixed z-[9999] bg-white rounded-xl shadow-2xl border border-stone-200 overflow-hidden">
                        {/* 검색 헤더 */}
                        <div className="p-3 border-b border-stone-100 bg-stone-50">
                            <div className="flex items-center gap-2">
                                <svg className="w-4 h-4 text-stone-400 shrink-0" 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>
                                <input
                                    ref={partnerSearchInputRef}
                                    type="text"
                                    value={partnerSearchQuery}
                                    onChange={(e) => handlePartnerSearchChange(e.target.value)}
                                    onKeyDown={(e) => {
                                        if (e.key === 'Escape') closePartnerSearch();
                                        if (e.key === 'Enter' && partnerSearchResults.length > 0) {
                                            e.preventDefault();
                                            handlePartnerSearchSelect(partnerSearchResults[0]);
                                        }
                                    }}
                                    className="flex-1 min-w-0 text-sm bg-transparent outline-none placeholder-stone-400"
                                    placeholder="거래처명/사업자번호 검색"
                                />
                                {partnerSearchLoading && (
                                    <svg className="w-4 h-4 animate-spin text-violet-500 shrink-0" fill="none" viewBox="0 0 24 24"><circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"/><path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/></svg>
                                )}
                                <button onClick={closePartnerSearch} className="p-0.5 text-stone-400 hover:text-stone-600 shrink-0">
                                    <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"/></svg>
                                </button>
                            </div>
                        </div>
                        {/* 검색 결과 */}
                        <div className="overflow-y-auto max-h-[300px]">
                            {partnerSearchResults.length === 0 ? (
                                <div className="px-4 py-8 text-center text-sm text-stone-400">
                                    {partnerSearchQuery ? '검색 결과가 없습니다' : '등록된 거래처가 없습니다'}
                                </div>
                            ) : (
                                partnerSearchResults.slice(0, 50).map((p) => (
                                    <button
                                        key={p.id}
                                        type="button"
                                        onClick={() => handlePartnerSearchSelect(p)}
                                        className="w-full text-left px-3 py-2 hover:bg-violet-50 transition-colors border-b border-stone-50 last:border-b-0"
                                    >
                                        <div className="text-sm font-medium text-stone-800 truncate">{p.name}</div>
                                        <div className="text-xs text-stone-400 font-mono">{p.biz_no || '-'}</div>
                                    </button>
                                ))
                            )}
                        </div>
                        {/* 결과 수 표시 */}
                        {partnerSearchResults.length > 0 && (
                            <div className="px-3 py-1.5 border-t border-stone-100 bg-stone-50 text-xs text-stone-400 text-right">
                                {partnerSearchResults.length}건
                            </div>
                        )}
                    </div>,
                    document.body
                )}
            </div>
        );
    };

    // ============================================
    // AccountCodeSelect - 계정과목 검색 드롭다운
    // ============================================
    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 s = search.toLowerCase();
            return code.code.toLowerCase().includes(s) || code.name.toLowerCase().includes(s);
        });

        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) => {
            onChange(code.code, code.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(() => { 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(() => { listRef.current?.children[newIndex]?.scrollIntoView({ block: 'nearest' }); }, 0);
            } else if (e.key === 'Enter' && filteredCodes.length > 0) {
                e.preventDefault();
                handleSelect(filteredCodes[highlightIndex >= 0 ? highlightIndex : 0]);
            } 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-violet-500 ring-2 ring-violet-500' : 'border-stone-200'
                    } bg-white`}
                >
                    <span className={displayText ? 'text-stone-900' : 'text-stone-400'}>
                        {displayText || '선택'}
                    </span>
                    <div className="flex items-center gap-1">
                        {value && (
                            <button onClick={handleClear} className="text-stone-400 hover:text-stone-600">
                                <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
                                </svg>
                            </button>
                        )}
                        <svg className={`w-3 h-3 text-stone-400 transition-transform ${isOpen ? 'rotate-180' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7" />
                        </svg>
                    </div>
                </div>
                {isOpen && (
                    <div className="absolute z-[9999] mt-1 w-56 bg-white border border-stone-200 rounded-lg shadow-xl">
                        <div className="p-2 border-b border-stone-100">
                            <input
                                type="text"
                                value={search}
                                onChange={(e) => setSearch(e.target.value)}
                                onKeyDown={handleKeyDown}
                                placeholder="코드 또는 이름 검색..."
                                className="w-full px-2 py-1 text-xs border border-stone-200 rounded focus:ring-1 focus:ring-violet-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-violet-600 text-white font-semibold'
                                                : value === code.code
                                                    ? 'bg-violet-100 text-violet-700'
                                                    : 'text-stone-700 hover:bg-violet-50'
                                        }`}
                                    >
                                        <span className={`font-mono ${index === highlightIndex ? 'text-white' : 'text-violet-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>
        );
    };

    // ============================================
    // JournalEntryModal - 분개 생성/수정 모달
    // ============================================
    const JournalEntryModal = ({ isOpen, onClose, onSave, onDelete, invoice, accountCodes = [] }) => {
        const formatCurrency = (val) => new Intl.NumberFormat('ko-KR').format(val || 0);
        const formatAmountInput = (val) => { const n = String(val).replace(/[^\d]/g, ''); return n ? Number(n).toLocaleString() : ''; };
        const parseAmountInput = (val) => parseInt(String(val).replace(/[^\d]/g, ''), 10) || 0;
        const isSales = invoice.invoiceType === 'sales' || invoice.invoice_type === 'sales';
        const supplyAmount = parseFloat(invoice.supplyAmount || invoice.supply_amount || 0);
        const taxAmount = parseFloat(invoice.taxAmount || invoice.tax_amount || 0);
        const totalAmount = parseFloat(invoice.totalAmount || invoice.total_amount || (supplyAmount + taxAmount));

        // 분개 라인 초기값
        const getDefaultLines = () => {
            if (isSales) {
                return [
                    { dc_type: 'debit', account_code: '108', account_name: '외상매출금', debit_amount: totalAmount, credit_amount: 0, description: '' },
                    { dc_type: 'credit', account_code: '401', account_name: '상품매출', debit_amount: 0, credit_amount: supplyAmount, description: '' },
                    { dc_type: 'credit', account_code: '255', account_name: '부가세예수금', debit_amount: 0, credit_amount: taxAmount, description: '' },
                ];
            } else {
                return [
                    { dc_type: 'debit', account_code: '501', account_name: '상품매입', debit_amount: supplyAmount, credit_amount: 0, description: '' },
                    { dc_type: 'debit', account_code: '135', account_name: '부가세대급금', debit_amount: taxAmount, credit_amount: 0, description: '' },
                    { dc_type: 'credit', account_code: '251', account_name: '외상매입금', debit_amount: 0, credit_amount: totalAmount, description: '' },
                ];
            }
        };

        const [lines, setLines] = useState(getDefaultLines());
        const [saving, setSaving] = useState(false);
        const [loadingJournal, setLoadingJournal] = useState(false);
        const [isEditMode, setIsEditMode] = useState(false);

        // 기존 분개 로드
        useEffect(() => {
            if (invoice.hasJournal) {
                setLoadingJournal(true);
                fetch(`${API.journals}?invoice_id=${invoice.id}`)
                    .then(res => res.json())
                    .then(data => {
                        if (data.success && data.data && data.data.length > 0) {
                            setLines(data.data);
                            setIsEditMode(true);
                        }
                    })
                    .catch(err => console.error('기존 분개 로드 오류:', err))
                    .finally(() => setLoadingJournal(false));
            }
        }, []);

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

        const totalDebit = lines.reduce((sum, l) => sum + (parseFloat(l.debit_amount) || 0), 0);
        const totalCredit = lines.reduce((sum, l) => sum + (parseFloat(l.credit_amount) || 0), 0);
        const isBalanced = Math.abs(totalDebit - totalCredit) < 1;

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

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

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

        const tradingPartner = isSales
            ? (invoice.invoiceeCorpName || invoice.invoicee_corp_name || '')
            : (invoice.invoicerCorpName || invoice.invoicer_corp_name || '');

        return (
            <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
                <div className="bg-white rounded-2xl shadow-2xl w-full max-w-3xl mx-4 max-h-[90vh] overflow-hidden">
                    <div className="p-6 border-b border-stone-100 flex items-center justify-between">
                        <h3 className="text-lg font-bold text-stone-900">
                            {isEditMode ? '분개 수정' : '분개 생성'}
                        </h3>
                        <button onClick={onClose} className="p-2 hover:bg-stone-100 rounded-lg transition-colors">
                            <svg className="w-5 h-5 text-stone-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
                            </svg>
                        </button>
                    </div>
                    <div className="p-6 overflow-y-auto max-h-[65vh] space-y-5">
                        {/* 세금계산서 정보 */}
                        <div className="bg-stone-50 rounded-xl p-4">
                            <h4 className="text-sm font-semibold text-stone-700 mb-3">세금계산서 정보</h4>
                            <div className="grid grid-cols-2 md:grid-cols-4 gap-3 text-sm">
                                <div><span className="text-stone-500">구분: </span><span className="font-medium">{isSales ? '매출' : '매입'}</span></div>
                                <div><span className="text-stone-500">거래처: </span><span className="font-medium">{tradingPartner}</span></div>
                                <div><span className="text-stone-500">공급가액: </span><span className="font-medium">{formatCurrency(supplyAmount)}</span></div>
                                <div><span className="text-stone-500">세액: </span><span className="font-medium">{formatCurrency(taxAmount)}</span></div>
                            </div>
                        </div>

                        {loadingJournal ? (
                            <div className="flex items-center justify-center py-8">
                                <div className="animate-spin rounded-full h-6 w-6 border-2 border-emerald-600 border-t-transparent"></div>
                                <span className="ml-2 text-sm text-stone-500">분개 데이터 로딩중...</span>
                            </div>
                        ) : (
                            /* 분개 라인 테이블 */
                            <div>
                                <h4 className="text-sm font-semibold text-stone-700 mb-3">분개 내역</h4>
                                <table className="w-full text-sm border border-stone-200 rounded-lg overflow-hidden">
                                    <thead>
                                        <tr className="bg-stone-100">
                                            <th className="px-3 py-2 text-center text-xs font-semibold text-stone-600 border-b border-stone-200">차/대</th>
                                            <th className="px-3 py-2 text-center text-xs font-semibold text-stone-600 border-b border-stone-200" colSpan="2">계정과목</th>
                                            <th className="px-3 py-2 text-center text-xs font-semibold text-stone-600 border-b border-stone-200">차변금액</th>
                                            <th className="px-3 py-2 text-center text-xs font-semibold text-stone-600 border-b border-stone-200">대변금액</th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        {lines.map((line, idx) => (
                                            <tr key={idx} className="border-b border-stone-100">
                                                <td className="px-3 py-2 text-center">
                                                    <button
                                                        type="button"
                                                        onClick={() => toggleDcType(idx)}
                                                        className={`px-2 py-0.5 rounded text-xs font-medium cursor-pointer hover:opacity-80 transition-opacity ${line.dc_type === 'debit' ? 'bg-blue-100 text-blue-700' : 'bg-red-100 text-red-700'}`}
                                                        title="클릭하여 차변/대변 전환"
                                                    >
                                                        {line.dc_type === 'debit' ? '차변' : '대변'}
                                                    </button>
                                                </td>
                                                <td className="px-3 py-2" colSpan="2">
                                                    <AccountCodeSelect
                                                        value={line.account_code}
                                                        onChange={(code, name) => {
                                                            setLines(prev => prev.map((l, i) => i === idx ? { ...l, account_code: code, account_name: name } : l));
                                                        }}
                                                        accountCodes={accountCodes}
                                                    />
                                                </td>
                                                <td className="px-3 py-2">
                                                    <input
                                                        type="text"
                                                        value={formatAmountInput(line.debit_amount)}
                                                        onChange={(e) => updateLine(idx, 'debit_amount', parseAmountInput(e.target.value))}
                                                        className="w-full px-2 py-1 border border-stone-200 rounded text-sm text-right focus:ring-1 focus:ring-violet-500 outline-none"
                                                    />
                                                </td>
                                                <td className="px-3 py-2">
                                                    <input
                                                        type="text"
                                                        value={formatAmountInput(line.credit_amount)}
                                                        onChange={(e) => updateLine(idx, 'credit_amount', parseAmountInput(e.target.value))}
                                                        className="w-full px-2 py-1 border border-stone-200 rounded text-sm text-right focus:ring-1 focus:ring-violet-500 outline-none"
                                                    />
                                                </td>
                                            </tr>
                                        ))}
                                        {/* 합계 */}
                                        <tr className={`font-bold ${isBalanced ? 'bg-green-50' : 'bg-red-50'}`}>
                                            <td colSpan="3" className="px-3 py-2 text-center text-sm">합계</td>
                                            <td className="px-3 py-2 text-right text-sm">{formatCurrency(totalDebit)}</td>
                                            <td className="px-3 py-2 text-right text-sm">{formatCurrency(totalCredit)}</td>
                                        </tr>
                                    </tbody>
                                </table>
                                {!isBalanced && (
                                    <p className="text-red-500 text-xs mt-2">차변과 대변의 합계가 일치하지 않습니다. (차이: {formatCurrency(Math.abs(totalDebit - totalCredit))})</p>
                                )}
                            </div>
                        )}
                    </div>
                    <div className="p-4 border-t border-stone-100 flex justify-between">
                        <div>
                            {isEditMode && (
                                <button
                                    onClick={handleDelete}
                                    disabled={saving}
                                    className="px-4 py-2 bg-red-50 text-red-600 rounded-lg text-sm font-medium hover:bg-red-100 transition-colors disabled:opacity-50"
                                >
                                    분개 삭제
                                </button>
                            )}
                        </div>
                        <div className="flex gap-3">
                            <button onClick={onClose} className="px-4 py-2 bg-stone-100 text-stone-700 rounded-lg text-sm font-medium hover:bg-stone-200 transition-colors">
                                취소
                            </button>
                            <button
                                onClick={handleSubmit}
                                disabled={saving || !isBalanced || loadingJournal}
                                className="px-6 py-2 bg-emerald-600 text-white rounded-lg text-sm font-medium hover:bg-emerald-700 transition-colors disabled:opacity-50 flex items-center gap-2"
                            >
                                {saving && <div className="animate-spin rounded-full h-4 w-4 border-2 border-white border-t-transparent"></div>}
                                {isEditMode ? '분개 수정' : '분개 저장'}
                            </button>
                        </div>
                    </div>
                </div>
            </div>
        );
    };

    // ============================================
    // CardTransactionPicker - 카드내역 선택 모달
    // ============================================
    const CardTransactionPicker = ({ onSelect, onClose }) => {
        const [transactions, setTransactions] = useState([]);
        const [loading, setLoading] = useState(true);
        const [search, setSearch] = useState('');
        const [startDate, setStartDate] = useState(formatKoreanDate(new Date(getKoreanNow().setMonth(getKoreanNow().getMonth() - 1))));
        const [endDate, setEndDate] = useState(formatKoreanDate(getKoreanNow()));

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

        const loadTransactions = async () => {
            setLoading(true);
            try {
                const params = new URLSearchParams({ startDate, endDate, search });
                const res = await fetch(`${API.cardTransactions}?${params}`);
                const data = await res.json();
                if (data.success) {
                    setTransactions(data.data || []);
                }
            } catch (err) {
                console.error('카드내역 조회 오류:', err);
            } finally {
                setLoading(false);
            }
        };

        useEffect(() => { loadTransactions(); }, []);

        return (
            <div className="fixed inset-0 bg-black/30 flex items-center justify-center z-[60]" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
                <div className="bg-white rounded-2xl shadow-2xl w-full max-w-2xl mx-4 max-h-[80vh] overflow-hidden">
                    <div className="p-4 border-b border-stone-100 flex items-center justify-between">
                        <h3 className="text-base font-bold text-stone-900">카드내역 불러오기</h3>
                        <button onClick={onClose} className="p-1 hover:bg-stone-100 rounded-lg transition-colors">
                            <svg className="w-5 h-5 text-stone-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
                            </svg>
                        </button>
                    </div>
                    {/* 검색 */}
                    <div className="p-4 border-b border-stone-100">
                        <div className="flex items-center gap-2">
                            <input type="date" value={startDate} onChange={(e) => setStartDate(e.target.value)} className="px-2 py-1.5 border border-stone-300 rounded text-sm" />
                            <span className="text-stone-400">~</span>
                            <input type="date" value={endDate} onChange={(e) => setEndDate(e.target.value)} className="px-2 py-1.5 border border-stone-300 rounded text-sm" />
                            <input
                                type="text"
                                value={search}
                                onChange={(e) => setSearch(e.target.value)}
                                placeholder="가맹점/승인번호"
                                className="flex-1 px-2 py-1.5 border border-stone-300 rounded text-sm"
                            />
                            <button onClick={loadTransactions} className="px-3 py-1.5 bg-violet-600 text-white rounded text-sm hover:bg-violet-700">조회</button>
                        </div>
                    </div>
                    {/* 목록 */}
                    <div className="overflow-y-auto max-h-[50vh]">
                        {loading ? (
                            <div className="flex items-center justify-center py-10">
                                <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-violet-600"></div>
                                <span className="ml-2 text-stone-500 text-sm">조회 중...</span>
                            </div>
                        ) : transactions.length === 0 ? (
                            <div className="py-10 text-center text-stone-400 text-sm">카드내역이 없습니다.</div>
                        ) : (
                            <table className="w-full text-sm">
                                <thead className="bg-stone-50 sticky top-0">
                                    <tr>
                                        <th className="px-3 py-2 text-left text-xs font-medium text-stone-600">날짜</th>
                                        <th className="px-3 py-2 text-left text-xs font-medium text-stone-600">가맹점</th>
                                        <th className="px-3 py-2 text-right text-xs font-medium text-stone-600">금액</th>
                                        <th className="px-3 py-2 text-center text-xs font-medium text-stone-600">승인번호</th>
                                        <th className="px-3 py-2 text-center text-xs font-medium text-stone-600">선택</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    {transactions.map((t) => (
                                        <tr key={t.id} className="border-b border-stone-100 hover:bg-violet-50 cursor-pointer" onClick={() => onSelect(t)}>
                                            <td className="px-3 py-2 text-xs text-stone-700 whitespace-nowrap">{t.useDate}</td>
                                            <td className="px-3 py-2 text-xs text-stone-700 truncate max-w-[200px]">{t.merchantName}</td>
                                            <td className="px-3 py-2 text-xs text-right font-medium text-stone-900">{t.approvalAmountFormatted}</td>
                                            <td className="px-3 py-2 text-xs text-center text-stone-500 font-mono">{t.approvalNum}</td>
                                            <td className="px-3 py-2 text-center">
                                                <button className="px-2 py-1 bg-violet-100 text-violet-700 rounded text-xs hover:bg-violet-200">선택</button>
                                            </td>
                                        </tr>
                                    ))}
                                </tbody>
                            </table>
                        )}
                    </div>
                </div>
            </div>
        );
    };

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