@extends('layouts.app')

@section('title', 'SAM E-Sign')

@section('content')
<meta name="csrf-token" content="{{ csrf_token() }}">
<div id="esign-dashboard-root"></div>
@endsection

@push('scripts')
@include('partials.react-cdn')
<script src="https://unpkg.com/lucide@0.469.0"></script>
@verbatim
<script type="text/babel">
const { useState, useEffect, useCallback } = React;

const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content || '';

const getHeaders = () => ({
    'Accept': 'application/json',
    'X-CSRF-TOKEN': csrfToken,
});

const STATUS_MAP = {
    draft: { label: '초안', color: 'bg-gray-100 text-gray-700' },
    pending: { label: '서명 대기', color: 'bg-blue-100 text-blue-700' },
    partially_signed: { label: '부분 서명', color: 'bg-yellow-100 text-yellow-700' },
    completed: { label: '완료', color: 'bg-green-100 text-green-700' },
    expired: { label: '만료', color: 'bg-red-100 text-red-700' },
    cancelled: { label: '취소', color: 'bg-gray-100 text-gray-500' },
    rejected: { label: '거절', color: 'bg-red-100 text-red-700' },
};

const StatusBadge = ({ status }) => {
    const s = STATUS_MAP[status] || { label: status, color: 'bg-gray-100 text-gray-700' };
    return <span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${s.color}`}>{s.label}</span>;
};

const StatsCard = ({ label, value, color }) => (
    <div className={`bg-white rounded-lg border p-4 ${color || ''}`}>
        <p className="text-sm text-gray-500">{label}</p>
        <p className="text-2xl font-bold mt-1">{value}</p>
    </div>
);

const RefreshIcon = () => (
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
        <polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15"/>
    </svg>
);

const TrashIcon = ({ size = 14 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
        <polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/>
    </svg>
);

// ─── 계약 목록 탭 ───
const ContractList = ({ onRefreshStats }) => {
    const [contracts, setContracts] = useState([]);
    const [loading, setLoading] = useState(true);
    const [filter, setFilter] = useState({ status: '', search: '' });
    const [page, setPage] = useState(1);
    const [pagination, setPagination] = useState({});
    const [selected, setSelected] = useState(new Set());
    const [deleting, setDeleting] = useState(false);

    const fetchContracts = useCallback(async () => {
        setLoading(true);
        try {
            const params = new URLSearchParams({ page, per_page: 20 });
            if (filter.status) params.append('status', filter.status);
            if (filter.search) params.append('search', filter.search);

            const res = await fetch(`/esign/contracts/list?${params}`, { headers: getHeaders() });
            const json = await res.json();
            if (json.success) {
                setContracts(json.data.data || []);
                setPagination({ current_page: json.data.current_page, last_page: json.data.last_page, total: json.data.total });
            }
        } catch (e) { console.error(e); }
        setLoading(false);
        setSelected(new Set());
    }, [filter, page]);

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

    const toggleSelect = (id) => {
        setSelected(prev => { const next = new Set(prev); next.has(id) ? next.delete(id) : next.add(id); return next; });
    };
    const toggleSelectAll = () => {
        selected.size === contracts.length ? setSelected(new Set()) : setSelected(new Set(contracts.map(c => c.id)));
    };

    const handleDelete = async () => {
        if (selected.size === 0) return;
        const activeIds = contracts.filter(c => selected.has(c.id) && ['pending', 'partially_signed'].includes(c.status));
        if (activeIds.length > 0) { alert('서명 진행 중인 계약은 삭제할 수 없습니다. 먼저 취소해 주세요.'); return; }
        if (!confirm(`선택한 ${selected.size}건의 계약을 휴지통으로 이동하시겠습니까?`)) return;

        setDeleting(true);
        try {
            const res = await fetch('/esign/contracts/destroy', {
                method: 'DELETE',
                headers: { ...getHeaders(), 'Content-Type': 'application/json' },
                body: JSON.stringify({ ids: [...selected] }),
            });
            const json = await res.json();
            if (json.success) { fetchContracts(); onRefreshStats(); }
            else alert(json.message || '삭제에 실패했습니다.');
        } catch (e) { alert('삭제 중 오류가 발생했습니다.'); }
        setDeleting(false);
    };

    return (
        <>
            {/* 필터 */}
            <div className="flex items-center gap-3 mb-4">
                <select value={filter.status} onChange={e => { setFilter(f => ({...f, status: e.target.value})); setPage(1); }}
                        className="border rounded-lg px-3 py-2 text-sm">
                    <option value="">전체 상태</option>
                    {Object.entries(STATUS_MAP).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
                </select>
                <input type="text" placeholder="제목 또는 코드 검색..." value={filter.search}
                       onChange={e => { setFilter(f => ({...f, search: e.target.value})); setPage(1); }}
                       className="border rounded-lg px-3 py-2 text-sm flex-1 max-w-xs" />
                <button onClick={handleDelete} disabled={deleting || selected.size === 0}
                        className={`ml-auto inline-flex items-center gap-1.5 px-3 py-2 rounded-lg text-sm font-medium transition-colors ${selected.size > 0 ? 'bg-red-600 text-white hover:bg-red-700' : 'bg-gray-100 text-gray-400 cursor-not-allowed'}`}>
                    <TrashIcon />
                    {deleting ? '이동 중...' : selected.size > 0 ? `${selected.size}건 삭제` : '선택 삭제'}
                </button>
            </div>

            {/* 목록 */}
            <div className="bg-white rounded-lg border overflow-hidden">
                <table className="w-full">
                    <thead className="bg-gray-50">
                        <tr>
                            <th className="px-3 py-3 w-10">
                                <input type="checkbox" checked={contracts.length > 0 && selected.size === contracts.length}
                                       onChange={toggleSelectAll} className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" />
                            </th>
                            <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">계약코드</th>
                            <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">제목</th>
                            <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">서명자</th>
                            <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">상태</th>
                            <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">생성일</th>
                            <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">만료일</th>
                        </tr>
                    </thead>
                    <tbody className="divide-y">
                        {loading ? (
                            <tr><td colSpan="7" className="px-4 py-8 text-center text-gray-400">로딩 중...</td></tr>
                        ) : contracts.length === 0 ? (
                            <tr><td colSpan="7" className="px-4 py-8 text-center text-gray-400">계약이 없습니다.</td></tr>
                        ) : contracts.map(c => (
                            <tr key={c.id} className={`hover:bg-gray-50 cursor-pointer ${selected.has(c.id) ? 'bg-blue-50' : ''}`}>
                                <td className="px-3 py-3" onClick={e => e.stopPropagation()}>
                                    <input type="checkbox" checked={selected.has(c.id)} onChange={() => toggleSelect(c.id)}
                                           className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" />
                                </td>
                                <td className="px-4 py-3 text-sm font-mono text-gray-600" onClick={() => location.href = `/esign/${c.id}`}>{c.contract_code}</td>
                                <td className="px-4 py-3 text-sm font-medium text-gray-900" onClick={() => location.href = `/esign/${c.id}`}>{c.title}</td>
                                <td className="px-4 py-3 text-sm text-gray-600" onClick={() => location.href = `/esign/${c.id}`}>
                                    {(c.signers || []).map(s => (
                                        <span key={s.id} className="inline-flex items-center mr-2">
                                            <span className={`w-2 h-2 rounded-full mr-1 ${s.status === 'signed' ? 'bg-green-500' : 'bg-gray-300'}`}></span>
                                            {s.name}
                                        </span>
                                    ))}
                                </td>
                                <td className="px-4 py-3" onClick={() => location.href = `/esign/${c.id}`}><StatusBadge status={c.status} /></td>
                                <td className="px-4 py-3 text-sm text-gray-500" onClick={() => location.href = `/esign/${c.id}`}>{c.created_at?.slice(0,10)}</td>
                                <td className="px-4 py-3 text-sm text-gray-500" onClick={() => location.href = `/esign/${c.id}`}>{c.expires_at?.slice(0,10)}</td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>

            {/* 페이지네이션 */}
            {pagination.last_page > 1 && (
                <div className="flex items-center justify-between mt-4">
                    <span className="text-sm text-gray-500">총 {pagination.total}건</span>
                    <div className="flex gap-1">
                        {Array.from({length: pagination.last_page}, (_, i) => i + 1).map(p => (
                            <button key={p} onClick={() => setPage(p)}
                                    className={`px-3 py-1 text-sm rounded ${p === pagination.current_page ? 'bg-blue-600 text-white' : 'bg-white border text-gray-700 hover:bg-gray-50'}`}>
                                {p}
                            </button>
                        ))}
                    </div>
                </div>
            )}
        </>
    );
};

// ─── 휴지통 탭 ───
const TrashList = ({ onRefreshStats }) => {
    const [contracts, setContracts] = useState([]);
    const [loading, setLoading] = useState(true);
    const [search, setSearch] = useState('');
    const [page, setPage] = useState(1);
    const [pagination, setPagination] = useState({});
    const [selected, setSelected] = useState(new Set());
    const [actionLoading, setActionLoading] = useState('');

    const fetchTrashed = useCallback(async () => {
        setLoading(true);
        try {
            const params = new URLSearchParams({ page, per_page: 20 });
            if (search) params.append('search', search);
            const res = await fetch(`/esign/contracts/trashed?${params}`, { headers: getHeaders() });
            const json = await res.json();
            if (json.success) {
                setContracts(json.data.data || []);
                setPagination({ current_page: json.data.current_page, last_page: json.data.last_page, total: json.data.total });
            }
        } catch (e) { console.error(e); }
        setLoading(false);
        setSelected(new Set());
    }, [search, page]);

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

    const toggleSelect = (id) => {
        setSelected(prev => { const next = new Set(prev); next.has(id) ? next.delete(id) : next.add(id); return next; });
    };
    const toggleSelectAll = () => {
        selected.size === contracts.length ? setSelected(new Set()) : setSelected(new Set(contracts.map(c => c.id)));
    };

    const handleRestore = async () => {
        if (selected.size === 0) return;
        if (!confirm(`선택한 ${selected.size}건의 계약을 복구하시겠습니까?`)) return;
        setActionLoading('restore');
        try {
            const res = await fetch('/esign/contracts/restore', {
                method: 'POST',
                headers: { ...getHeaders(), 'Content-Type': 'application/json' },
                body: JSON.stringify({ ids: [...selected] }),
            });
            const json = await res.json();
            if (json.success) { fetchTrashed(); onRefreshStats(); }
            else alert(json.message || '복구에 실패했습니다.');
        } catch (e) { alert('복구 중 오류가 발생했습니다.'); }
        setActionLoading('');
    };

    const handleForceDelete = async () => {
        if (selected.size === 0) return;
        if (!confirm(`선택한 ${selected.size}건의 계약을 영구 삭제하시겠습니까?\n\n이 작업은 되돌릴 수 없습니다.`)) return;
        setActionLoading('force');
        try {
            const res = await fetch('/esign/contracts/force-destroy', {
                method: 'DELETE',
                headers: { ...getHeaders(), 'Content-Type': 'application/json' },
                body: JSON.stringify({ ids: [...selected] }),
            });
            const json = await res.json();
            if (json.success) { fetchTrashed(); onRefreshStats(); }
            else alert(json.message || '삭제에 실패했습니다.');
        } catch (e) { alert('삭제 중 오류가 발생했습니다.'); }
        setActionLoading('');
    };

    const timeAgo = (dateStr) => {
        if (!dateStr) return '';
        const diff = Date.now() - new Date(dateStr).getTime();
        const mins = Math.floor(diff / 60000);
        if (mins < 1) return '방금 전';
        if (mins < 60) return `${mins}분 전`;
        const hours = Math.floor(mins / 60);
        if (hours < 24) return `${hours}시간 전`;
        const days = Math.floor(hours / 24);
        return `${days}일 전`;
    };

    return (
        <>
            {/* 필터 + 액션 */}
            <div className="flex items-center gap-3 mb-4">
                <input type="text" placeholder="제목 또는 코드 검색..." value={search}
                       onChange={e => { setSearch(e.target.value); setPage(1); }}
                       className="border rounded-lg px-3 py-2 text-sm flex-1 max-w-xs" />
                <div className="ml-auto flex items-center gap-2">
                    <button onClick={handleRestore} disabled={selected.size === 0 || !!actionLoading}
                            className={`inline-flex items-center gap-1.5 px-3 py-2 rounded-lg text-sm font-medium transition-colors ${selected.size > 0 && !actionLoading ? 'bg-blue-600 text-white hover:bg-blue-700' : 'bg-gray-100 text-gray-400 cursor-not-allowed'}`}>
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                            <polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 102.13-9.36L1 10"/>
                        </svg>
                        {actionLoading === 'restore' ? '복구 중...' : selected.size > 0 ? `${selected.size}건 복구` : '선택 복구'}
                    </button>
                    <button onClick={handleForceDelete} disabled={selected.size === 0 || !!actionLoading}
                            className={`inline-flex items-center gap-1.5 px-3 py-2 rounded-lg text-sm font-medium transition-colors ${selected.size > 0 && !actionLoading ? 'bg-red-600 text-white hover:bg-red-700' : 'bg-gray-100 text-gray-400 cursor-not-allowed'}`}>
                        <TrashIcon />
                        {actionLoading === 'force' ? '삭제 중...' : selected.size > 0 ? `${selected.size}건 영구삭제` : '영구삭제'}
                    </button>
                </div>
            </div>

            {/* 목록 */}
            <div className="bg-white rounded-lg border overflow-hidden">
                <table className="w-full">
                    <thead className="bg-gray-50">
                        <tr>
                            <th className="px-3 py-3 w-10">
                                <input type="checkbox" checked={contracts.length > 0 && selected.size === contracts.length}
                                       onChange={toggleSelectAll} className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" />
                            </th>
                            <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">계약코드</th>
                            <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">제목</th>
                            <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">서명자</th>
                            <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">상태</th>
                            <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">삭제일</th>
                        </tr>
                    </thead>
                    <tbody className="divide-y">
                        {loading ? (
                            <tr><td colSpan="6" className="px-4 py-8 text-center text-gray-400">로딩 중...</td></tr>
                        ) : contracts.length === 0 ? (
                            <tr><td colSpan="6" className="px-4 py-12 text-center text-gray-400">
                                <div className="flex flex-col items-center gap-2">
                                    <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="text-gray-300">
                                        <polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/>
                                    </svg>
                                    <span>휴지통이 비어있습니다.</span>
                                </div>
                            </td></tr>
                        ) : contracts.map(c => (
                            <tr key={c.id} className={`hover:bg-gray-50 ${selected.has(c.id) ? 'bg-blue-50' : ''}`}>
                                <td className="px-3 py-3">
                                    <input type="checkbox" checked={selected.has(c.id)} onChange={() => toggleSelect(c.id)}
                                           className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" />
                                </td>
                                <td className="px-4 py-3 text-sm font-mono text-gray-400">{c.contract_code}</td>
                                <td className="px-4 py-3 text-sm text-gray-500">{c.title}</td>
                                <td className="px-4 py-3 text-sm text-gray-400">
                                    {(c.signers || []).map(s => <span key={s.id} className="mr-2">{s.name}</span>)}
                                </td>
                                <td className="px-4 py-3"><StatusBadge status={c.status} /></td>
                                <td className="px-4 py-3 text-sm text-gray-400" title={c.deleted_at?.slice(0,19).replace('T',' ')}>{timeAgo(c.deleted_at)}</td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>

            {/* 페이지네이션 */}
            {pagination.last_page > 1 && (
                <div className="flex items-center justify-between mt-4">
                    <span className="text-sm text-gray-500">총 {pagination.total}건</span>
                    <div className="flex gap-1">
                        {Array.from({length: pagination.last_page}, (_, i) => i + 1).map(p => (
                            <button key={p} onClick={() => setPage(p)}
                                    className={`px-3 py-1 text-sm rounded ${p === pagination.current_page ? 'bg-blue-600 text-white' : 'bg-white border text-gray-700 hover:bg-gray-50'}`}>
                                {p}
                            </button>
                        ))}
                    </div>
                </div>
            )}
        </>
    );
};

// ─── 설정 탭 ───
const SettingsTab = () => {
    const [stamp, setStamp] = useState(null); // { image_path, image_url }
    const [loading, setLoading] = useState(true);
    const [uploading, setUploading] = useState(false);
    const [deleting, setDeleting] = useState(false);
    const fileRef = React.useRef(null);

    const fetchStamp = async () => {
        setLoading(true);
        try {
            const res = await fetch('/esign/contracts/stamp', { headers: getHeaders() });
            const json = await res.json();
            if (json.success) setStamp(json.data);
        } catch (e) { console.error(e); }
        setLoading(false);
    };

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

    const handleUpload = async (e) => {
        const file = e.target.files[0];
        if (!file) return;
        if (file.size > 5 * 1024 * 1024) { alert('파일 크기는 5MB 이하여야 합니다.'); return; }
        setUploading(true);
        try {
            const base64 = await new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.onload = () => resolve(reader.result.split(',')[1]);
                reader.onerror = reject;
                reader.readAsDataURL(file);
            });
            const res = await fetch('/esign/contracts/stamp', {
                method: 'POST',
                headers: { ...getHeaders(), 'Content-Type': 'application/json' },
                body: JSON.stringify({ stamp_image_data: base64 }),
            });
            const json = await res.json();
            if (json.success) {
                setStamp(json.data);
            } else {
                const errMsg = json.errors?.stamp_image_data?.[0] || json.message || '업로드에 실패했습니다.';
                alert(errMsg);
            }
        } catch (e) { alert('업로드 중 오류가 발생했습니다.'); }
        setUploading(false);
        if (fileRef.current) fileRef.current.value = '';
    };

    const handleDelete = async () => {
        if (!confirm('법인도장을 삭제하시겠습니까?')) return;
        setDeleting(true);
        try {
            const res = await fetch('/esign/contracts/stamp', {
                method: 'DELETE',
                headers: { ...getHeaders(), 'Content-Type': 'application/json' },
            });
            const json = await res.json();
            if (json.success) setStamp(null);
            else alert(json.message || '삭제에 실패했습니다.');
        } catch (e) { alert('삭제 중 오류가 발생했습니다.'); }
        setDeleting(false);
    };

    if (loading) return <div className="text-center py-8 text-gray-400">로딩 중...</div>;

    return (
        <div className="max-w-xl">
            <div className="bg-white rounded-lg border p-5">
                <h2 className="text-sm font-semibold text-gray-900 mb-1">법인도장 관리</h2>
                <p className="text-xs text-gray-400 mb-4">등록된 법인도장은 새 계약 생성 시 자동으로 적용됩니다.</p>

                {stamp ? (
                    <div className="flex items-start gap-4">
                        <div className="border rounded-lg p-3 bg-gray-50">
                            <img src={stamp.image_url} alt="법인도장" className="h-24 w-24 object-contain" />
                        </div>
                        <div className="flex-1 pt-2">
                            <p className="text-sm text-green-700 font-medium mb-1">법인도장이 등록되어 있습니다.</p>
                            <p className="text-xs text-gray-400 mb-3">새 계약 생성 시 작성자 서명에 자동 적용됩니다.</p>
                            <div className="flex gap-2">
                                <button onClick={() => fileRef.current?.click()} disabled={uploading}
                                        className="px-3 py-1.5 border border-gray-300 rounded-md text-xs font-medium text-gray-700 hover:bg-gray-50 transition-colors disabled:opacity-50">
                                    {uploading ? '교체 중...' : '이미지 교체'}
                                </button>
                                <button onClick={handleDelete} disabled={deleting}
                                        className="px-3 py-1.5 border border-red-300 rounded-md text-xs font-medium text-red-600 hover:bg-red-50 transition-colors disabled:opacity-50">
                                    {deleting ? '삭제 중...' : '삭제'}
                                </button>
                            </div>
                        </div>
                        <input ref={fileRef} type="file" accept="image/*" onChange={handleUpload} className="hidden" />
                    </div>
                ) : (
                    <div className="border-2 border-dashed border-gray-200 rounded-lg p-6 text-center">
                        <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="mx-auto text-gray-300 mb-2" strokeLinecap="round" strokeLinejoin="round">
                            <rect x="3" y="3" width="18" height="18" rx="3"/>
                            <circle cx="12" cy="12" r="4"/>
                        </svg>
                        <p className="text-sm text-gray-500 mb-3">등록된 법인도장이 없습니다.</p>
                        <button onClick={() => fileRef.current?.click()} disabled={uploading}
                                className="px-4 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 transition-colors disabled:opacity-50">
                            {uploading ? '업로드 중...' : '법인도장 이미지 등록'}
                        </button>
                        <input ref={fileRef} type="file" accept="image/*" onChange={handleUpload} className="hidden" />
                        <p className="text-xs text-gray-400 mt-2">PNG, JPG 형식 (최대 5MB)</p>
                    </div>
                )}
            </div>
        </div>
    );
};

// ─── App ───
const App = () => {
    const [tab, setTab] = useState(() => {
        const hash = window.location.hash.replace('#', '');
        return ['contracts', 'trash', 'settings'].includes(hash) ? hash : 'contracts';
    }); // 'contracts' | 'trash' | 'settings'
    const [stats, setStats] = useState({});
    const [trashCount, setTrashCount] = useState(0);

    const fetchStats = useCallback(async () => {
        try {
            const res = await fetch('/esign/contracts/stats', { headers: getHeaders() });
            const json = await res.json();
            if (json.success) setStats(json.data);
        } catch (e) { console.error(e); }
    }, []);

    const fetchTrashCount = useCallback(async () => {
        try {
            const res = await fetch('/esign/contracts/trashed?per_page=1', { headers: getHeaders() });
            const json = await res.json();
            if (json.success) setTrashCount(json.data.total || 0);
        } catch (e) { console.error(e); }
    }, []);

    const refreshAll = () => { fetchStats(); fetchTrashCount(); };

    useEffect(() => { fetchStats(); fetchTrashCount(); }, []);

    return (
        <div className="p-4 sm:p-6">
            <div className="flex items-center justify-between mb-6">
                <div className="flex items-center gap-2">
                    <h1 className="text-2xl font-bold text-gray-900">SAM E-Sign</h1>
                    <button onClick={refreshAll} title="새로고침"
                            className="w-8 h-8 flex items-center justify-center rounded-lg text-gray-400 hover:text-gray-600 hover:bg-gray-100 transition-colors">
                        <RefreshIcon />
                    </button>
                </div>
                <a href="/esign/create"
                   className="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm font-medium"
                   hx-boost="false">
                    + 새 계약 생성
                </a>
            </div>

            {/* 통계 카드 (계약 목록 탭에서만) */}
            {tab === 'contracts' && (
                <div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-7 gap-3 mb-6">
                    <StatsCard label="전체" value={stats.total || 0} />
                    <StatsCard label="초안" value={stats.draft || 0} />
                    <StatsCard label="서명 대기" value={stats.pending || 0} color="border-blue-200" />
                    <StatsCard label="부분 서명" value={stats.partially_signed || 0} color="border-yellow-200" />
                    <StatsCard label="완료" value={stats.completed || 0} color="border-green-200" />
                    <StatsCard label="만료" value={stats.expired || 0} />
                    <StatsCard label="취소/거절" value={(stats.cancelled || 0) + (stats.rejected || 0)} />
                </div>
            )}

            {/* 탭 */}
            <div className="flex items-center gap-1 border-b mb-4">
                <button onClick={() => setTab('contracts')}
                        className={`px-4 py-2.5 text-sm font-medium border-b-2 transition-colors -mb-px ${tab === 'contracts' ? 'border-blue-600 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700'}`}>
                    계약 목록
                </button>
                <button onClick={() => setTab('trash')}
                        className={`px-4 py-2.5 text-sm font-medium border-b-2 transition-colors -mb-px inline-flex items-center gap-1.5 ${tab === 'trash' ? 'border-blue-600 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700'}`}>
                    <TrashIcon size={14} />
                    휴지통
                    {trashCount > 0 && (
                        <span className={`text-xs px-1.5 py-0.5 rounded-full ${tab === 'trash' ? 'bg-blue-100 text-blue-600' : 'bg-gray-100 text-gray-500'}`}>{trashCount}</span>
                    )}
                </button>
                <button onClick={() => setTab('settings')}
                        className={`px-4 py-2.5 text-sm font-medium border-b-2 transition-colors -mb-px inline-flex items-center gap-1.5 ${tab === 'settings' ? 'border-blue-600 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700'}`}>
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                        <circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 112.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z"/>
                    </svg>
                    설정
                </button>
            </div>

            {/* 탭 콘텐츠 */}
            {tab === 'contracts' && <ContractList onRefreshStats={refreshAll} />}
            {tab === 'trash' && <TrashList onRefreshStats={refreshAll} />}
            {tab === 'settings' && <SettingsTab />}
        </div>
    );
};

ReactDOM.createRoot(document.getElementById('esign-dashboard-root')).render(<App />);
</script>
@endverbatim
@endpush
