import React, {useEffect, useMemo, useState} from 'react';
import {Link, usePage} from '@inertiajs/react';
import MainLayout from '@/layouts/MainLayout';
import AppPageHeader from '@/components/AppPageHeader';
import {makeGetRequest, makePostRequest} from '@/lib/request';
import {notify} from '@/lib/notify';
import {useCurrencyFormatter} from '@/lib/currency';

const PAYMENT_METHODS = [
    {value: 'check', label: 'Check'},
    {value: 'credit_card', label: 'Credit card'},
    {value: 'debit_card', label: 'Debit card'},
    {value: 'wire_transfer', label: 'Wire transfer'},
    {value: 'ach', label: 'ACH'},
    {value: 'trust_withdrawal', label: 'Trust withdrawal'},
    {value: 'cash', label: 'Cash'},
];

function dateLabel(value: any): string {
    return value ? new Date(value).toLocaleDateString() : '-';
}

function titleCase(value: string): string {
    return (value || '-').replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
}

function todayIso(): string {
    return new Date().toISOString().slice(0, 10);
}

export default function Index(): JSX.Element {
    const {auth} = usePage<{ auth: { user: any } }>().props;
    const token = auth?.user?.token ?? auth?.user?.api_token ?? undefined;
    const money = useCurrencyFormatter(token);

    const [payments, setPayments] = useState<any[]>([]);
    const [loading, setLoading] = useState(false);
    const [page, setPage] = useState(1);
    const [query, setQuery] = useState('');
    const [method, setMethod] = useState('');
    const [meta, setMeta] = useState<any>(null);
    const [recordOpen, setRecordOpen] = useState(false);
    const [allocatePayment, setAllocatePayment] = useState<any | null>(null);

    useEffect(() => {
        fetchPayments();
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [page, method, token]);

    useEffect(() => {
        const t = setTimeout(() => { setPage(1); fetchPayments(1, query, method); }, 350);
        return () => clearTimeout(t);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [query]);

    async function fetchPayments(p = page, q = query, m = method) {
        setLoading(true);
        try {
            const params = new URLSearchParams({page: String(p)});
            if (q.trim()) params.append('search', q.trim());
            if (m) params.append('payment_method', m);
            const res = await makeGetRequest(`/api/payments?${params}`, {token});
            const payload = res.data?.result ?? res.data ?? {};
            const list = payload?.data ?? payload ?? [];
            setPayments(Array.isArray(list) ? list : []);
            setMeta(payload?.meta ?? (payload?.data ? {current_page: payload.current_page ?? p, last_page: payload.last_page ?? 1, total: payload.total ?? 0} : null));
        } catch (e: any) {
            notify.toastErrorMessage(e?.response?.data?.message || 'Failed to load payments');
        } finally {
            setLoading(false);
        }
    }

    const summary = useMemo(() => ({
        received: payments.reduce((sum, payment) => sum + Number(payment.amount ?? 0), 0),
        allocated: payments.reduce((sum, payment) => sum + Number(payment.allocated_amount ?? 0), 0),
        unallocated: payments.reduce((sum, payment) => sum + Number(payment.unallocated_balance ?? 0), 0),
    }), [payments]);

    const gotoPage = (p: number) => {
        if (p < 1 || p > (meta?.last_page ?? p)) return;
        setPage(p);
    };

    return (
        <MainLayout>
            <AppPageHeader title="Payments" subtitle="Billing" />

            <div className="grid grid-cols-12 gap-6 mb-6">
                <div className="col-span-12 sm:col-span-4"><div className="box"><div className="box-body"><p className="text-sm text-gray-500 mb-1">Received</p><p className="text-2xl font-semibold">{money(summary.received)}</p></div></div></div>
                <div className="col-span-12 sm:col-span-4"><div className="box"><div className="box-body"><p className="text-sm text-gray-500 mb-1">Allocated</p><p className="text-2xl font-semibold text-success">{money(summary.allocated)}</p></div></div></div>
                <div className="col-span-12 sm:col-span-4"><div className="box"><div className="box-body"><p className="text-sm text-gray-500 mb-1">Unallocated</p><p className="text-2xl font-semibold text-warning">{money(summary.unallocated)}</p></div></div></div>
            </div>

            <div className="box"><div className="box-body">
                <div className="flex flex-wrap justify-between gap-4 mb-5">
                    <div className="flex flex-wrap items-center gap-3"><div className="relative sm:max-w-xs max-w-[220px]"><div className="absolute inset-y-0 end-0 flex items-center pointer-events-none pe-4"><i className="ti ti-search"></i></div><input type="text" className="p-2 pe-10 ti-form-input" placeholder="Search payments" value={query} onChange={e => setQuery(e.target.value)} /></div><select className="ti-form-input w-auto" value={method} onChange={e => { setMethod(e.target.value); setPage(1); }}><option value="">All methods</option>{PAYMENT_METHODS.map(m => <option key={m.value} value={m.value}>{m.label}</option>)}</select></div>
                    <div className="flex gap-2"><Link href="/payments/allocations" className="ti-btn ti-btn-soft-secondary py-2 px-3">Allocations</Link><button type="button" className="ti-btn ti-btn-primary py-2 px-3" onClick={() => setRecordOpen(true)}><i className="ri ri-add-line mr-2"></i>Record Payment</button></div>
                </div>

                <div className="rounded-sm overflow-auto todo-table w-full"><table className="ti-custom-table ti-custom-table-head whitespace-nowrap w-full"><thead className="bg-gray-100"><tr><th>Date</th><th>Client</th><th>Method</th><th>Reference</th><th>Amount</th><th>Allocated</th><th>Unallocated</th><th>Recorded By</th><th className="!text-end">Action</th></tr></thead><tbody>
                    {loading ? <tr><td colSpan={9} className="text-center py-8">Loading...</td></tr> : payments.length === 0 ? <tr><td colSpan={9} className="text-center py-8">No payments found.</td></tr> : payments.map(payment => <tr key={payment.id}><td>{dateLabel(payment.payment_date)}</td><td>{payment.client?.name ?? '-'}</td><td>{titleCase(payment.payment_method)}</td><td>{payment.reference_number ?? '-'}</td><td>{money(payment.amount)}</td><td>{money(payment.allocated_amount)}</td><td>{money(payment.unallocated_balance)}</td><td>{payment.recorded_by?.name ?? payment.recordedBy?.name ?? '-'}</td><td className="text-end"><button type="button" disabled={Number(payment.unallocated_balance ?? 0) <= 0} className="w-8 h-8 ti-btn rounded-full p-0 ti-btn-soft-primary disabled:opacity-40" title="Allocate" onClick={() => setAllocatePayment(payment)}><i className="ti ti-arrows-split"></i></button></td></tr>)}
                </tbody></table></div>
                <div className="flex items-center justify-between mt-4"><div className="text-sm text-gray-600">showing {payments.length} of {meta?.total ?? 0} items</div><div className="flex items-center gap-2"><button type="button" disabled={(meta?.current_page ?? 1) <= 1} onClick={() => gotoPage((meta?.current_page ?? 1) - 1)} className="px-2 py-1 border rounded disabled:opacity-40">Prev</button>{Array.from({length: meta?.last_page ?? 1}).map((_, i) => <button key={i + 1} type="button" onClick={() => gotoPage(i + 1)} className={`px-2 py-1 border rounded ${i + 1 === (meta?.current_page ?? page) ? 'bg-indigo-600 text-white' : ''}`}>{i + 1}</button>)}<button type="button" disabled={(meta?.current_page ?? 1) >= (meta?.last_page ?? 1)} onClick={() => gotoPage((meta?.current_page ?? 1) + 1)} className="px-2 py-1 border rounded disabled:opacity-40">Next</button></div></div>
            </div></div>

            {recordOpen && <RecordPaymentModal token={token} onClose={() => setRecordOpen(false)} onSaved={() => { setRecordOpen(false); fetchPayments(); }} />}
            {allocatePayment && <AllocatePaymentModal token={token} payment={allocatePayment} money={money} onClose={() => setAllocatePayment(null)} onSaved={() => { setAllocatePayment(null); fetchPayments(); }} />}
        </MainLayout>
    );
}

function RecordPaymentModal({token, onClose, onSaved}: { token?: string; onClose: () => void; onSaved: () => void }): JSX.Element {
    const [clients, setClients] = useState<any[]>([]);
    const [clientQuery, setClientQuery] = useState('');
    const [showClients, setShowClients] = useState(false);
    const [form, setForm] = useState({client_profile_id: '', payment_date: todayIso(), amount: '', payment_method: 'check', reference_number: '', notes: ''});
    const [errors, setErrors] = useState<Record<string, string[]>>({});
    const [submitting, setSubmitting] = useState(false);

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

    async function fetchClients() {
        const res = await makeGetRequest('/api/clients?per_page=200', {token});
        const payload = res.data?.result ?? res.data ?? {};
        const list = payload?.data ?? payload ?? [];
        setClients(Array.isArray(list) ? list : []);
    }

    const filtered = clients.filter(c => !clientQuery.trim() || (c.name ?? '').toLowerCase().includes(clientQuery.toLowerCase()) || (c.email ?? '').toLowerCase().includes(clientQuery.toLowerCase())).slice(0, 50);

    const submit = async (e: React.FormEvent) => {
        e.preventDefault();
        setErrors({});
        setSubmitting(true);
        try {
            await makePostRequest('/api/payments', {...form, amount: Number(form.amount), reference_number: form.reference_number || null, notes: form.notes || null}, {token});
            notify.toastSuccessMessage('Payment recorded');
            onSaved();
        } catch (err: any) {
            if (err?.response?.data?.errors) setErrors(err.response.data.errors);
            else notify.toastErrorMessage(err?.response?.data?.message || 'Failed to record payment');
        } finally {
            setSubmitting(false);
        }
    };

    return <div role="dialog" aria-modal="true" className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 backdrop-blur-sm p-4"><div className="bg-white rounded-xl shadow-xl w-full max-w-lg"><form onSubmit={submit} noValidate><div className="flex items-center justify-between px-5 py-4 border-b border-gray-200"><h3 className="text-base font-semibold text-gray-800">Record Payment</h3><button type="button" className="p-1.5 text-gray-400 hover:text-gray-600 rounded" onClick={onClose}><i className="ri ri-close-line text-lg"></i></button></div><div className="px-5 py-5 space-y-4"><div className="relative"><label className="ti-form-label">Client</label><input type="text" className="ti-form-input" placeholder="Search client" value={clientQuery} onFocus={() => setShowClients(true)} onBlur={() => setTimeout(() => setShowClients(false), 150)} onChange={e => { setClientQuery(e.target.value); setShowClients(true); setForm(f => ({...f, client_profile_id: ''})); }} />{showClients && <ul className="absolute z-20 left-0 right-0 bg-white border rounded mt-1 max-h-52 overflow-auto shadow">{filtered.map(c => <li key={c.id} className="px-3 py-2 hover:bg-gray-100 cursor-pointer text-sm" onMouseDown={e => e.preventDefault()} onClick={() => { setForm(f => ({...f, client_profile_id: c.id})); setClientQuery(c.name); setShowClients(false); }}><div className="font-medium">{c.name}</div><div className="text-xs text-gray-500">{c.email ?? ''}</div></li>)}</ul>}{errors.client_profile_id && <p className="text-sm text-red-600 mt-1">{errors.client_profile_id[0]}</p>}</div><div className="grid grid-cols-1 sm:grid-cols-2 gap-4"><div><label className="ti-form-label">Date</label><input type="date" className="ti-form-input" value={form.payment_date} onChange={e => setForm(f => ({...f, payment_date: e.target.value}))} /></div><div><label className="ti-form-label">Amount</label><input type="number" step="0.01" min="0" className="ti-form-input" value={form.amount} onChange={e => setForm(f => ({...f, amount: e.target.value}))} />{errors.amount && <p className="text-sm text-red-600 mt-1">{errors.amount[0]}</p>}</div></div><div><label className="ti-form-label">Method</label><select className="ti-form-input" value={form.payment_method} onChange={e => setForm(f => ({...f, payment_method: e.target.value}))}>{PAYMENT_METHODS.map(m => <option key={m.value} value={m.value}>{m.label}</option>)}</select></div><div><label className="ti-form-label">Reference</label><input type="text" className="ti-form-input" value={form.reference_number} onChange={e => setForm(f => ({...f, reference_number: e.target.value}))} /></div><div><label className="ti-form-label">Notes</label><textarea className="ti-form-input" rows={3} value={form.notes} onChange={e => setForm(f => ({...f, notes: e.target.value}))} /></div></div><div className="flex items-center justify-end gap-2 px-5 py-4 border-t border-gray-200"><button type="button" onClick={onClose} className="px-4 py-2 text-sm border rounded-lg hover:bg-gray-50">Cancel</button><button type="submit" disabled={submitting} className="ti-btn ti-btn-primary px-4 py-2">{submitting ? 'Recording...' : 'Record Payment'}</button></div></form></div></div>;
}

function AllocatePaymentModal({token, payment, money, onClose, onSaved}: { token?: string; payment: any; money: (value: any) => string; onClose: () => void; onSaved: () => void }): JSX.Element {
    const [invoices, setInvoices] = useState<any[]>([]);
    const [invoiceId, setInvoiceId] = useState('');
    const [amount, setAmount] = useState(String(payment.unallocated_balance ?? ''));
    const [submitting, setSubmitting] = useState(false);

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

    async function fetchInvoices() {
        const params = new URLSearchParams({client_id: String(payment.client_profile_id), per_page: '100'});
        const res = await makeGetRequest(`/api/invoices?${params}`, {token});
        const payload = res.data?.result ?? res.data ?? {};
        const list = payload?.data ?? payload ?? [];
        setInvoices((Array.isArray(list) ? list : []).filter((invoice: any) => Number(invoice.balance_due ?? 0) > 0 && !['cancelled', 'written_off'].includes(invoice.status)));
    }

    const submit = async (e: React.FormEvent) => {
        e.preventDefault();
        if (!invoiceId || Number(amount) <= 0) return;
        setSubmitting(true);
        try {
            await makePostRequest(`/api/payments/${payment.id}/allocate`, {invoice_id: Number(invoiceId), amount: Number(amount)}, {token});
            notify.toastSuccessMessage('Payment allocated');
            onSaved();
        } catch (err: any) {
            notify.toastErrorMessage(err?.response?.data?.message || 'Failed to allocate payment');
        } finally {
            setSubmitting(false);
        }
    };

    return <div role="dialog" aria-modal="true" className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 backdrop-blur-sm p-4"><div className="bg-white rounded-xl shadow-xl w-full max-w-md"><form onSubmit={submit}><div className="flex items-center justify-between px-5 py-4 border-b border-gray-200"><h3 className="text-base font-semibold text-gray-800">Allocate Payment</h3><button type="button" className="p-1.5 text-gray-400 hover:text-gray-600 rounded" onClick={onClose}><i className="ri ri-close-line text-lg"></i></button></div><div className="px-5 py-5 space-y-4"><p className="text-sm text-gray-600">Unallocated balance: <span className="font-semibold">{money(payment.unallocated_balance)}</span></p><div><label className="ti-form-label">Invoice</label><select className="ti-form-input" value={invoiceId} onChange={e => { const id = e.target.value; setInvoiceId(id); const invoice = invoices.find(item => String(item.id) === id); if (invoice) setAmount(String(Math.min(Number(payment.unallocated_balance ?? 0), Number(invoice.balance_due ?? 0)))); }}><option value="">Select invoice</option>{invoices.map(invoice => <option key={invoice.id} value={invoice.id}>{invoice.invoice_number} - {money(invoice.balance_due)}</option>)}</select></div><div><label className="ti-form-label">Amount</label><input type="number" step="0.01" min="0.01" max={payment.unallocated_balance} className="ti-form-input" value={amount} onChange={e => setAmount(e.target.value)} /></div></div><div className="flex items-center justify-end gap-2 px-5 py-4 border-t border-gray-200"><button type="button" onClick={onClose} className="px-4 py-2 text-sm border rounded-lg hover:bg-gray-50">Cancel</button><button type="submit" disabled={submitting || !invoiceId || Number(amount) <= 0} className="ti-btn ti-btn-primary px-4 py-2">{submitting ? 'Allocating...' : 'Allocate'}</button></div></form></div></div>;
}
