<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>전자서명 - SAM E-Sign</title>
    @vite(['resources/css/app.css'])
</head>
<body class="bg-gray-50 min-h-screen">
<div id="esign-sign-root" data-token="{{ $token }}"></div>

<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script>
(function(){var w=console.warn;console.warn=function(){if(typeof arguments[0]==='string'&&arguments[0].indexOf('in-browser Babel')>-1)return;w.apply(console,arguments)};})();
</script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/signature_pad@4.1.7/dist/signature_pad.umd.min.js"></script>
@verbatim
<script type="text/babel">
const { useState, useEffect, useCallback, useRef } = React;

const TOKEN = document.getElementById('esign-sign-root')?.dataset.token;

// 인라인 스타일 상수
const STYLES = {
    canvasWrap: { height: '200px' },
    canvas: { width: '100%', height: '100%', touchAction: 'none', background: '#fff' },
    previewWrap: { height: '200px' },
};

const App = () => {
    const [contract, setContract] = useState(null);
    const [signer, setSigner] = useState(null);
    const [step, setStep] = useState('document'); // document, sign, confirm
    const [consent, setConsent] = useState(false);
    const [submitting, setSubmitting] = useState(false);
    const [error, setError] = useState('');
    const [signatureData, setSignatureData] = useState(null);
    const [signMode, setSignMode] = useState('stamp'); // 'signature' | 'stamp'
    const [stampPreview, setStampPreview] = useState(null);
    const [stampData, setStampData] = useState(null);
    const canvasRef = useRef(null);
    const padRef = useRef(null);
    const stampInputRef = useRef(null);

    // 계약 정보 로드
    const fetchContract = useCallback(async () => {
        try {
            const res = await fetch(`/esign/sign/${TOKEN}/api/contract`, {
                headers: { 'Accept': 'application/json' },
            });
            const json = await res.json();
            if (json.success) {
                setContract(json.data.contract);
                setSigner(json.data.signer);
                // 서명 불가 상태면 에러 표시
                if (!json.data.is_signable && json.data.status_message) {
                    setError(json.data.status_message);
                }
            } else {
                setError(json.message);
            }
        } catch (e) { setError('서버 연결 실패'); }
    }, []);

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

    // signature_pad 초기화
    useEffect(() => {
        if (step === 'sign' && canvasRef.current && !padRef.current) {
            const canvas = canvasRef.current;
            canvas.width = canvas.offsetWidth * 2;
            canvas.height = canvas.offsetHeight * 2;
            canvas.getContext('2d').scale(2, 2);
            padRef.current = new SignaturePad(canvas, {
                backgroundColor: 'rgba(0,0,0,0)',
                penColor: 'rgb(0, 0, 0)',
            });
        }
    }, [step]);

    const clearSignature = () => {
        if (padRef.current) padRef.current.clear();
    };

    const removeBackground = (img) => {
        // 도장 이미지 최대 크기 제한 (500px) - 용량 절감
        const MAX_SIZE = 500;
        let w = img.naturalWidth, h = img.naturalHeight;
        if (w > MAX_SIZE || h > MAX_SIZE) {
            const ratio = Math.min(MAX_SIZE / w, MAX_SIZE / h);
            w = Math.round(w * ratio);
            h = Math.round(h * ratio);
        }

        const canvas = document.createElement('canvas');
        canvas.width = w;
        canvas.height = h;
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0, w, h);

        const imageData = ctx.getImageData(0, 0, w, h);
        const data = imageData.data;
        const threshold = 210;

        for (let i = 0; i < data.length; i += 4) {
            const r = data[i], g = data[i + 1], b = data[i + 2];
            const brightness = r * 0.299 + g * 0.587 + b * 0.114;
            if (brightness > threshold) {
                data[i + 3] = 0;
            } else {
                const fade = Math.max(0, (brightness - (threshold - 40)) / 40);
                if (fade > 0) {
                    data[i + 3] = Math.round(data[i + 3] * (1 - fade));
                }
            }
        }

        ctx.putImageData(imageData, 0, 0);
        return canvas.toDataURL('image/png');
    };

    const handleStampUpload = (e) => {
        const file = e.target.files?.[0];
        if (!file) return;
        if (file.size > 5 * 1024 * 1024) {
            alert('5MB 이하의 이미지만 업로드 가능합니다.');
            e.target.value = '';
            return;
        }
        if (!file.type.match(/^image\/(png|jpeg|jpg)$/)) {
            alert('PNG 또는 JPG 이미지만 업로드 가능합니다.');
            e.target.value = '';
            return;
        }
        const reader = new FileReader();
        reader.onload = (ev) => {
            const img = new Image();
            img.onload = () => {
                const transparentDataUrl = removeBackground(img);
                setStampPreview(transparentDataUrl);
                setStampData(transparentDataUrl.replace('data:image/png;base64,', ''));
            };
            img.src = ev.target.result;
        };
        reader.readAsDataURL(file);
    };

    const goToSign = () => {
        if (!consent) { alert('동의 항목을 체크해 주세요.'); return; }
        if (signMode === 'stamp') {
            if (signer?.has_stamp) {
                submitStamp();
            } else {
                submitStampWithUpload();
            }
        } else {
            setStep('sign');
        }
    };

    const confirmSignature = () => {
        if (!padRef.current || padRef.current.isEmpty()) {
            alert('서명을 입력해 주세요.'); return;
        }
        const data = padRef.current.toDataURL('image/png');
        setSignatureData(data.replace('data:image/png;base64,', ''));
        setStep('confirm');
    };

    const submitStamp = async () => {
        setSubmitting(true);
        setError('');
        try {
            const res = await fetch(`/esign/sign/${TOKEN}/api/submit`, {
                method: 'POST',
                headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
                body: JSON.stringify({ use_stamp: true }),
            });
            const json = await res.json();
            if (json.success) {
                location.href = `/esign/sign/${TOKEN}/done`;
            } else {
                setError(json.message || '도장 제출에 실패했습니다.');
            }
        } catch (e) { setError('서버 오류'); }
        setSubmitting(false);
    };

    const submitStampWithUpload = async () => {
        if (!stampData) { alert('도장 이미지를 업로드해 주세요.'); return; }
        setSubmitting(true);
        setError('');
        try {
            const res = await fetch(`/esign/sign/${TOKEN}/api/submit`, {
                method: 'POST',
                headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
                body: JSON.stringify({ use_stamp: true, stamp_image: stampData }),
            });
            const json = await res.json();
            if (json.success) {
                location.href = `/esign/sign/${TOKEN}/done`;
            } else {
                setError(json.message || '도장 제출에 실패했습니다.');
            }
        } catch (e) { setError('서버 오류'); }
        setSubmitting(false);
    };

    const submitSignature = async () => {
        setSubmitting(true);
        setError('');
        try {
            const res = await fetch(`/esign/sign/${TOKEN}/api/submit`, {
                method: 'POST',
                headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
                body: JSON.stringify({ signature_image: signatureData }),
            });
            const json = await res.json();
            if (json.success) {
                location.href = `/esign/sign/${TOKEN}/done`;
            } else {
                setError(json.message || '서명 제출에 실패했습니다.');
                setStep('sign');
            }
        } catch (e) { setError('서버 오류'); }
        setSubmitting(false);
    };

    const rejectContract = async () => {
        const reason = prompt('거절 사유를 입력해 주세요:');
        if (!reason) return;
        try {
            const res = await fetch(`/esign/sign/${TOKEN}/api/reject`, {
                method: 'POST',
                headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
                body: JSON.stringify({ reason }),
            });
            const json = await res.json();
            if (json.success) {
                alert('서명이 거절되었습니다.');
                location.href = `/esign/sign/${TOKEN}/done`;
            } else { alert(json.message); }
        } catch (e) { alert('서버 오류'); }
    };

    if (!contract) return (
        <div className="flex items-center justify-center min-h-screen">
            <p className="text-gray-400">{error || '로딩 중...'}</p>
        </div>
    );

    return (
        <div className="min-h-screen flex flex-col">
            {/* 상단 바 */}
            <div className="bg-white border-b px-4 py-3 flex items-center justify-between">
                <div>
                    <h1 className="font-semibold text-gray-900">{contract.title}</h1>
                    <p className="text-xs text-gray-500">{signer?.name} 님의 전자서명</p>
                </div>
                <div className="flex gap-2">
                    {step !== 'confirm' && (
                        <button onClick={rejectContract} className="px-3 py-1.5 text-sm border border-red-300 text-red-600 rounded-lg hover:bg-red-50">
                            거절
                        </button>
                    )}
                </div>
            </div>

            {error && <div className="bg-red-50 border-b border-red-200 text-red-700 px-4 py-2 text-sm">{error}</div>}

            {/* 문서 확인 단계 */}
            {step === 'document' && (
                <div className="flex flex-col p-4 max-w-2xl mx-auto w-full">
                    <div className="bg-white rounded-lg border p-6 mb-4">
                        <h2 className="text-lg font-semibold mb-4">계약 문서 확인</h2>
                        <div className="bg-gray-100 rounded-lg p-8 text-center mb-4">
                            <p className="text-gray-500 mb-3">PDF 문서</p>
                            <a href={`/esign/sign/${TOKEN}/api/document`} target="_blank"
                               className="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 text-sm">
                                문서 열기 / 다운로드
                            </a>
                        </div>
                        {(signer?.has_stamp || signer?.role === 'counterpart' || signer?.role === 'creator') && (
                            <div className="border-t pt-4 mt-4">
                                <p className="text-sm font-medium text-gray-700 mb-3">서명 방법을 선택해 주세요.</p>
                                <div className="flex gap-3">
                                    <label className={`flex-1 flex items-center gap-2 p-3 border-2 rounded-lg cursor-pointer transition-colors ${signMode === 'signature' ? 'border-blue-500 bg-blue-50' : 'border-gray-200 hover:border-gray-300'}`}>
                                        <input type="radio" name="signMode" value="signature" checked={signMode === 'signature'}
                                               onChange={() => setSignMode('signature')} className="text-blue-600 focus:ring-blue-500" />
                                        <div>
                                            <span className="text-sm font-medium text-gray-900">직접 서명</span>
                                            <p className="text-xs text-gray-500">터치/마우스로 서명</p>
                                        </div>
                                    </label>
                                    <label className={`flex-1 flex items-center gap-2 p-3 border-2 rounded-lg cursor-pointer transition-colors ${signMode === 'stamp' ? 'border-blue-500 bg-blue-50' : 'border-gray-200 hover:border-gray-300'}`}>
                                        <input type="radio" name="signMode" value="stamp" checked={signMode === 'stamp'}
                                               onChange={() => setSignMode('stamp')} className="text-blue-600 focus:ring-blue-500" />
                                        <div>
                                            <span className="text-sm font-medium text-gray-900">{signer?.has_stamp ? '법인도장' : '도장'}</span>
                                            <p className="text-xs text-gray-500">{signer?.has_stamp ? '등록된 도장 사용' : '도장 이미지 업로드'}</p>
                                        </div>
                                    </label>
                                </div>
                                {signMode === 'stamp' && !signer?.has_stamp && (
                                    <div className="mt-4 p-4 border-2 border-dashed border-gray-300 rounded-lg">
                                        {!stampPreview ? (
                                            <div className="text-center">
                                                <p className="text-sm text-gray-500 mb-3">도장 이미지를 업로드해 주세요.</p>
                                                <p className="text-xs text-gray-400 mb-3">PNG, JPG (5MB 이하)</p>
                                                <input ref={stampInputRef} type="file" accept="image/png,image/jpeg"
                                                       onChange={handleStampUpload} className="hidden" />
                                                <button type="button" onClick={() => stampInputRef.current?.click()}
                                                        className="px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 text-sm border border-gray-300">
                                                    파일 선택
                                                </button>
                                            </div>
                                        ) : (
                                            <div className="text-center">
                                                <p className="text-xs text-green-600 mb-2">배경이 자동 제거되었습니다</p>
                                                <div className="rounded-lg p-3 mb-3 flex items-center justify-center" style={{height: '150px', background: 'repeating-conic-gradient(#e5e7eb 0% 25%, #fff 0% 50%) 0 0 / 16px 16px'}}>
                                                    <img src={stampPreview} alt="도장 미리보기" className="max-h-full max-w-full object-contain" />
                                                </div>
                                                <button type="button" onClick={() => { setStampPreview(null); setStampData(null); if (stampInputRef.current) stampInputRef.current.value = ''; }}
                                                        className="px-4 py-2 text-sm text-gray-600 hover:text-gray-800 border border-gray-300 rounded-lg hover:bg-gray-50">
                                                    다시 선택
                                                </button>
                                            </div>
                                        )}
                                    </div>
                                )}
                            </div>
                        )}
                        <div className="border-t pt-4 mt-4">
                            <label className="flex items-start gap-3 cursor-pointer">
                                <input type="checkbox" checked={consent} onChange={e => setConsent(e.target.checked)}
                                       className="mt-0.5 w-5 h-5 rounded border-gray-300 text-blue-600 focus:ring-blue-500" />
                                <span className="text-sm text-gray-700">
                                    위 계약서의 내용을 확인하였으며, 전자서명에 동의합니다.
                                    전자서명법에 의거하여 전자서명은 자필서명과 동일한 법적 효력을 가집니다.
                                </span>
                            </label>
                        </div>
                    </div>
                    <button onClick={goToSign} disabled={!consent || submitting}
                            className="w-full py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 font-medium disabled:opacity-50">
                        {submitting ? '처리 중...' : (signMode === 'stamp' ? '도장 찍기' : '서명하기')}
                    </button>
                </div>
            )}

            {/* 서명 단계 */}
            {step === 'sign' && (
                <div className="flex flex-col p-4 max-w-2xl mx-auto w-full">
                    <div className="bg-white rounded-lg border p-6 mb-4">
                        <div className="flex items-center justify-between mb-4">
                            <h2 className="text-lg font-semibold">서명 입력</h2>
                            <button onClick={clearSignature} className="text-sm text-gray-500 hover:text-gray-700">지우기</button>
                        </div>
                        <p className="text-sm text-gray-500 mb-3">아래 영역에 서명을 입력해 주세요.</p>
                        <div className="border-2 border-dashed border-gray-300 rounded-lg overflow-hidden" style={STYLES.canvasWrap}>
                            <canvas ref={canvasRef} style={STYLES.canvas} />
                        </div>
                    </div>
                    <div className="flex gap-3">
                        <button onClick={() => setStep('document')} className="flex-1 py-3 border rounded-lg text-gray-700 hover:bg-gray-50">
                            이전
                        </button>
                        <button onClick={confirmSignature} className="flex-1 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 font-medium">
                            서명 확인
                        </button>
                    </div>
                </div>
            )}

            {/* 확인 단계 */}
            {step === 'confirm' && (
                <div className="flex flex-col p-4 max-w-2xl mx-auto w-full">
                    <div className="bg-white rounded-lg border p-6 mb-4">
                        <h2 className="text-lg font-semibold mb-4">서명 확인</h2>
                        <p className="text-sm text-gray-600 mb-4">아래 서명이 맞는지 확인해 주세요.</p>
                        <div className="border rounded-lg p-4 bg-gray-50 flex items-center justify-center" style={STYLES.previewWrap}>
                            {signatureData && <img src={`data:image/png;base64,${signatureData}`} alt="서명" className="max-h-full" />}
                        </div>
                    </div>
                    <div className="flex gap-3">
                        <button onClick={() => { setStep('sign'); padRef.current = null; }} className="flex-1 py-3 border rounded-lg text-gray-700 hover:bg-gray-50">
                            다시 서명
                        </button>
                        <button onClick={submitSignature} disabled={submitting}
                                className="flex-1 py-3 bg-green-600 text-white rounded-lg hover:bg-green-700 font-medium disabled:opacity-50">
                            {submitting ? '제출 중...' : '서명 제출'}
                        </button>
                    </div>
                </div>
            )}
        </div>
    );
};

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