import React, {FormEvent, useEffect, useMemo, useState} from 'react';
import {Head} from '@inertiajs/react';
import axios from 'axios';
import SignatureCanvas from '@/Pages/Documents/partials/SignatureCanvas';

type Props = {token: string};
type Mode = 'saved' | 'drawn' | 'uploaded';

export default function DocumentSigning({token}: Props): JSX.Element {
    const [summary, setSummary] = useState<any | null>(null);
    const [details, setDetails] = useState<any | null>(null);
    const [session, setSession] = useState(() => sessionStorage.getItem(`signature-session:${token}`) ?? '');
    const [pdfUrl, setPdfUrl] = useState('');
    const [signatureImages, setSignatureImages] = useState<Record<number, string>>({});
    const [otp, setOtp] = useState('');
    const [otpSent, setOtpSent] = useState(false);
    const [mode, setMode] = useState<Mode>('drawn');
    const [selectedSignatureId, setSelectedSignatureId] = useState('');
    const [signatureFile, setSignatureFile] = useState<File | null>(null);
    const [saveSignature, setSaveSignature] = useState(true);
    const [signatureLabel, setSignatureLabel] = useState('My signature');
    const [pageNumber, setPageNumber] = useState('1');
    const [position, setPosition] = useState('bottom-right');
    const [size, setSize] = useState('20');
    const [consent, setConsent] = useState(false);
    const [loading, setLoading] = useState(true);
    const [submitting, setSubmitting] = useState(false);
    const [complete, setComplete] = useState(false);
    const [error, setError] = useState('');
    const [notice, setNotice] = useState('');

    const headers = useMemo(() => session ? {'X-Signature-Session': session} : {}, [session]);

    useEffect(() => {
        axios.get(`/api/signing/${token}`).then(response => {
            setSummary(response.data.result);
            if (session) loadSigningWorkspace(session);
        }).catch(handleFatal).finally(() => setLoading(false));
        return () => {
            if (pdfUrl) URL.revokeObjectURL(pdfUrl);
            Object.values(signatureImages).forEach(URL.revokeObjectURL);
        };
    }, [token]);

    async function loadSigningWorkspace(activeSession = session) {
        try {
            const authHeaders = {'X-Signature-Session': activeSession};
            const [detailResponse, documentResponse] = await Promise.all([
                axios.get(`/api/signing/${token}/details`, {headers: authHeaders}),
                axios.get(`/api/signing/${token}/document`, {headers: authHeaders, responseType: 'blob'}),
            ]);
            const result = detailResponse.data.result;
            setDetails(result);
            setPdfUrl(current => {
                if (current) URL.revokeObjectURL(current);
                return URL.createObjectURL(documentResponse.data);
            });
            if (result.saved_signatures?.length) {
                const preferred = result.saved_signatures.find((item: any) => item.is_default) ?? result.saved_signatures[0];
                setSelectedSignatureId(String(preferred.id));
                setMode('saved');
                await loadSignatureImages(result.saved_signatures, activeSession);
            }
            setError('');
        } catch (requestError: any) {
            sessionStorage.removeItem(`signature-session:${token}`);
            setSession('');
            if (requestError?.response?.status !== 401) handleFatal(requestError);
        }
    }

    async function loadSignatureImages(signatures: any[], activeSession: string) {
        const loaded: Record<number, string> = {};
        await Promise.all(signatures.map(async signature => {
            const response = await axios.get(`/api/signing/${token}/signatures/${signature.id}/image`, {
                headers: {'X-Signature-Session': activeSession}, responseType: 'blob',
            });
            loaded[signature.id] = URL.createObjectURL(response.data);
        }));
        setSignatureImages(current => {
            Object.values(current).forEach(URL.revokeObjectURL);
            return loaded;
        });
    }

    async function sendOtp() {
        setSubmitting(true); setError(''); setNotice('');
        try {
            await axios.post(`/api/signing/${token}/otp`);
            setOtpSent(true);
            setNotice(`A six-digit code was sent to ${summary?.masked_email}.`);
        } catch (requestError: any) {
            setError(message(requestError, 'Unable to send the verification code.'));
        } finally { setSubmitting(false); }
    }

    async function verifyOtp(event: FormEvent) {
        event.preventDefault(); setSubmitting(true); setError('');
        try {
            const response = await axios.post(`/api/signing/${token}/verify`, {otp});
            const activeSession = response.data.result.session;
            sessionStorage.setItem(`signature-session:${token}`, activeSession);
            setSession(activeSession);
            await loadSigningWorkspace(activeSession);
        } catch (requestError: any) {
            setError(message(requestError, 'Unable to verify the code.'));
        } finally { setSubmitting(false); }
    }

    async function submitSignature() {
        if (mode === 'saved' && !selectedSignatureId) return setError('Select a saved signature.');
        if (mode !== 'saved' && !signatureFile) return setError('Draw or upload your signature first.');
        if (!consent) return setError('Confirm that you agree to sign this document electronically.');
        setSubmitting(true); setError('');
        const positions: Record<string, [number, number]> = {
            'bottom-left': [8, 82], 'bottom-center': [40, 82], 'bottom-right': [72, 82],
        };
        const [x, y] = positions[position];
        const data = new FormData();
        if (mode === 'saved') data.append('signatory_signature_id', selectedSignatureId);
        if (mode !== 'saved' && signatureFile) data.append('signature_file', signatureFile);
        data.append('signature_method', mode);
        data.append('page_number', pageNumber);
        data.append('x_percent', String(x)); data.append('y_percent', String(y)); data.append('width_percent', size);
        data.append('consent', '1');
        if (mode !== 'saved' && saveSignature) {
            data.append('save_signature', '1'); data.append('signature_label', signatureLabel);
        }
        try {
            await axios.post(`/api/signing/${token}/submit`, data, {headers});
            sessionStorage.removeItem(`signature-session:${token}`);
            if (pdfUrl) URL.revokeObjectURL(pdfUrl);
            setComplete(true); setSession(''); setDetails(null);
        } catch (requestError: any) {
            setError(message(requestError, 'Unable to submit your signature.'));
        } finally { setSubmitting(false); }
    }

    function handleFatal(requestError: any) {
        const status = requestError?.response?.status;
        setError(status === 410 ? 'This signing link has expired or has already been used.' : message(requestError, 'This signing request is unavailable.'));
    }

    if (loading) return <Shell title="Secure document signing"><Centered><i className="fa fa-spinner fa-spin me-2" />Loading secure request…</Centered></Shell>;
    if (complete) return <Shell title="Signature submitted"><Centered><div className="mx-auto mb-5 flex h-20 w-20 items-center justify-center rounded-full bg-green-100 text-4xl text-green-600"><i className="fa fa-check" /></div><h1 className="text-2xl font-semibold">Thank you. Your signature was submitted.</h1><p className="mt-3 text-gray-500">The secure link is now closed. The requester will review the PDF with your signature in the selected position before a new document version is created.</p></Centered></Shell>;
    if (!summary) return <Shell title="Signing request unavailable"><Centered><Error text={error} /></Centered></Shell>;

    if (!session || !details) return <Shell title="Verify your identity">
        <div className="mx-auto max-w-lg rounded-2xl border bg-white p-8 shadow-sm">
            <div className="mb-6 flex h-14 w-14 items-center justify-center rounded-2xl bg-blue-50 text-2xl text-primary"><i className="fa fa-shield" /></div>
            <p className="text-sm font-medium text-primary">Secure signature request</p>
            <h1 className="mt-1 text-2xl font-semibold text-gray-900">{summary.document_title}</h1>
            <p className="mt-2 text-sm text-gray-500">Requested by {summary.requested_by}. Verify the email address {summary.masked_email} before reviewing the document.</p>
            {error ? <Error text={error} /> : null}{notice ? <div className="mt-4 rounded-lg bg-green-50 p-3 text-sm text-green-700">{notice}</div> : null}
            {!otpSent ? <div className="mt-6 rounded-xl border border-blue-100 bg-blue-50 p-4">
                <p className="mb-3 text-sm text-gray-700">We will email a one-time verification code to <strong>{summary.masked_email}</strong>.</p>
                <button
                    type="button"
                    className="block min-h-[48px] w-full rounded-lg border border-blue-700 px-5 py-3 text-center font-semibold shadow-sm disabled:cursor-not-allowed disabled:opacity-60"
                    style={{backgroundColor: '#1d4ed8', color: '#ffffff'}}
                    disabled={submitting}
                    onClick={sendOtp}
                >
                    {submitting ? <><i className="fa fa-spinner fa-spin me-2" />Sending code…</> : <><i className="fa fa-envelope-o me-2" />Send verification code</>}
                </button>
            </div> : <form className="mt-6" onSubmit={verifyOtp}><label className="text-sm font-medium text-gray-700">Six-digit verification code</label><input className="mt-2 w-full rounded-lg border-gray-300 py-3 text-center text-2xl tracking-[0.5em]" inputMode="numeric" autoComplete="one-time-code" maxLength={6} required value={otp} onChange={event => setOtp(event.target.value.replace(/\D/g, ''))} /><button className="mt-4 block min-h-[48px] w-full rounded-lg border border-blue-700 px-5 py-3 font-semibold text-white shadow-sm disabled:cursor-not-allowed disabled:opacity-60" style={{backgroundColor: '#1d4ed8', color: '#ffffff'}} disabled={submitting || otp.length !== 6}>{submitting ? 'Verifying…' : 'Verify and continue'}</button><button type="button" className="mt-3 w-full text-sm text-primary" disabled={submitting} onClick={sendOtp}>Send a new code</button></form>}
            <p className="mt-6 text-center text-xs text-gray-400">The signing link expires {new Date(summary.expires_at).toLocaleString()}.</p>
        </div>
    </Shell>;

    return <Shell title={`Sign ${details.document.title}`}>
        <div className="grid min-h-[calc(100vh-88px)] grid-cols-1 bg-gray-100 lg:grid-cols-[minmax(0,1fr)_420px]">
            <main className="flex min-h-[600px] flex-col p-4 lg:p-7">
                <div className="mb-4 flex flex-wrap items-center justify-between gap-3"><div><p className="text-xs font-semibold uppercase tracking-wider text-primary">Document preview</p><h1 className="text-xl font-semibold text-gray-900">{details.document.title}</h1><p className="text-sm text-gray-500">{details.document.matter_reference ?? 'No matter reference'} · {details.document.version}</p></div><span className="rounded-full bg-white px-4 py-2 text-sm text-gray-600 shadow-sm"><i className="fa fa-lock me-2 text-green-600" />Email verified</span></div>
                <div className="min-h-[600px] flex-1 overflow-hidden rounded-xl bg-gray-700 shadow-inner">{pdfUrl ? <iframe title="Document to sign" src={pdfUrl} className="h-full min-h-[75vh] w-full border-0" /> : <div className="flex h-full items-center justify-center text-white"><i className="fa fa-spinner fa-spin me-2" />Preparing preview…</div>}</div>
            </main>
            <aside className="border-l bg-white p-6 shadow-xl lg:sticky lg:top-0 lg:h-screen lg:overflow-y-auto">
                <p className="text-xs font-semibold uppercase tracking-wider text-gray-400">Signing as</p><h2 className="mt-1 text-lg font-semibold">{details.signatory.name}</h2><p className="text-sm text-gray-500">{details.signatory.email}</p>
                {details.request.message ? <div className="mt-5 rounded-lg bg-blue-50 p-3 text-sm text-blue-800">{details.request.message}</div> : null}
                <div className="mt-6 grid grid-cols-3 gap-1 rounded-xl bg-gray-100 p-1">{(['saved', 'drawn', 'uploaded'] as Mode[]).map(item => <button key={item} type="button" onClick={() => {setMode(item); setSignatureFile(null);}} className={`rounded-lg px-2 py-2 text-sm font-medium ${mode === item ? 'bg-white text-primary shadow-sm' : 'text-gray-500'}`}>{item === 'drawn' ? 'Draw' : item === 'uploaded' ? 'Upload' : 'Saved'}</button>)}</div>
                <div className="mt-4">
                    {mode === 'saved' ? details.saved_signatures.length ? <div className="space-y-2">{details.saved_signatures.map((item: any) => <label key={item.id} className={`flex cursor-pointer items-center gap-3 rounded-xl border p-3 ${selectedSignatureId === String(item.id) ? 'border-primary bg-blue-50' : ''}`}><input type="radio" checked={selectedSignatureId === String(item.id)} onChange={() => setSelectedSignatureId(String(item.id))} /><img src={signatureImages[item.id]} className="h-12 w-32 bg-white object-contain" alt={item.label} /><span className="text-sm font-medium">{item.label}</span></label>)}</div> : <div className="rounded-xl border border-dashed p-5 text-center text-sm text-gray-500">No saved signature exists for this email yet. Use Draw or Upload.</div> : null}
                    {mode === 'drawn' ? <SignatureCanvas onChange={setSignatureFile} /> : null}
                    {mode === 'uploaded' ? <label className="block rounded-xl border-2 border-dashed p-6 text-center"><i className="fa fa-upload mb-3 block text-2xl text-primary" /><span className="text-sm font-medium">Upload a PNG signature</span><span className="mt-2 block text-xs leading-5 text-gray-500">Accepted dimensions: 20×10 to 2000×1000 pixels.<br />Recommended: approximately 900×300 pixels with a transparent background.<br />Maximum file size: 2 MB.</span><input type="file" accept="image/png,.png" className="mt-3 block w-full text-sm" onChange={event => setSignatureFile(event.target.files?.[0] ?? null)} /></label> : null}
                </div>
                {mode !== 'saved' ? <div className="mt-4 space-y-3"><label className="flex items-center gap-2 text-sm"><input type="checkbox" checked={saveSignature} onChange={event => setSaveSignature(event.target.checked)} />Save this signature for future requests to this email</label>{saveSignature ? <input className="w-full rounded-lg border-gray-300" value={signatureLabel} onChange={event => setSignatureLabel(event.target.value)} placeholder="Signature name" /> : null}</div> : null}
                <div className="mt-6 grid grid-cols-3 gap-3"><Field label="Page"><select value={pageNumber} onChange={event => setPageNumber(event.target.value)}>{Array.from({length: details.document.page_count || 1}, (_, index) => <option key={index + 1} value={index + 1}>{index + 1}</option>)}</select></Field><Field label="Position"><select value={position} onChange={event => setPosition(event.target.value)}><option value="bottom-left">Left</option><option value="bottom-center">Centre</option><option value="bottom-right">Right</option></select></Field><Field label="Size"><select value={size} onChange={event => setSize(event.target.value)}><option value="12">Small</option><option value="20">Medium</option><option value="28">Large</option></select></Field></div>
                <label className="mt-6 flex items-start gap-3 rounded-xl bg-gray-50 p-4 text-sm text-gray-600"><input type="checkbox" className="mt-1" checked={consent} onChange={event => setConsent(event.target.checked)} /><span>I confirm that I am {details.signatory.name}, I have reviewed this document, and I agree to apply this electronic signature.</span></label>
                <div className="sticky bottom-0 -mx-6 mt-6 border-t border-gray-200 bg-white px-6 pb-2 pt-4 shadow-[0_-8px_20px_rgba(15,23,42,0.08)]">
                    {error ? <Error text={error} /> : null}
                    <button
                        type="button"
                        onClick={submitSignature}
                        disabled={submitting}
                        className="block min-h-[50px] w-full rounded-xl border border-blue-700 px-5 py-3.5 text-center font-semibold shadow-sm disabled:cursor-not-allowed disabled:opacity-60"
                        style={{backgroundColor: '#1d4ed8', color: '#ffffff'}}
                    >
                        {submitting ? <><i className="fa fa-spinner fa-spin me-2" />Saving signature…</> : <><i className="fa fa-check me-2" />Save and submit signature</>}
                    </button>
                    <p className="mt-3 text-center text-xs text-gray-400">After submission, this secure link immediately expires.</p>
                </div>
            </aside>
        </div>
    </Shell>;
}

function Shell({title, children}: {title: string; children: React.ReactNode}): JSX.Element {
    return <div className="min-h-screen bg-slate-50"><Head><title>{title}</title></Head><header className="flex h-[72px] items-center justify-between border-b bg-white px-5 lg:px-8"><div className="flex items-center gap-3"><div className="flex h-10 w-10 items-center justify-center rounded-xl bg-primary text-white"><i className="fa fa-file-text-o" /></div><div><div className="font-semibold text-gray-900">{import.meta.env.VITE_APP_NAME || 'Law Firm'}</div><div className="text-xs text-gray-400">Secure document signing</div></div></div><div className="flex items-center gap-2 text-xs text-gray-500"><i className="fa fa-lock text-green-600" />Protected by email verification</div></header>{children}</div>;
}

function Centered({children}: {children: React.ReactNode}): JSX.Element {
    return <main className="mx-auto max-w-2xl px-6 py-24 text-center">{children}</main>;
}

function Field({label, children}: {label: string; children: React.ReactNode}): JSX.Element {
    return <label className="text-xs font-medium text-gray-500">{label}{React.cloneElement(children as React.ReactElement, {className: 'mt-1 w-full rounded-lg border-gray-300 text-sm'})}</label>;
}

function Error({text}: {text: string}): JSX.Element {
    return <div className="mt-4 rounded-lg bg-red-50 p-3 text-sm text-red-700"><i className="fa fa-exclamation-circle me-2" />{text}</div>;
}

function message(error: any, fallback: string): string {
    const errors = error?.response?.data?.errors;
    return errors ? Object.values(errors).flat().join(' ') : error?.response?.data?.message || fallback;
}
