import React, {useEffect, useMemo, useState} from 'react';
import {Link, router, 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';

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

function defaultDueDate(): string {
    const d = new Date();
    d.setDate(d.getDate() + 30);
    return d.toISOString().slice(0, 10);
}

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

function hours(minutes: number): string {
    return `${Math.round((Number(minutes ?? 0) / 60) * 100) / 100}h`;
}

interface FormState {
    client_profile_id: number | '';
    client_matter_id: number | '';
    issued_date: string;
    due_date: string;
    tax_rate: number | '';
    notes: string;
    payment_instructions: string;
    time_entry_ids: number[];
    expense_ids: number[];
}

const emptyForm = (): FormState => ({
    client_profile_id: '',
    client_matter_id: '',
    issued_date: todayIso(),
    due_date: defaultDueDate(),
    tax_rate: 0,
    notes: '',
    payment_instructions: '',
    time_entry_ids: [],
    expense_ids: [],
});

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

    const [form, setForm] = useState<FormState>(emptyForm());
    const [matters, setMatters] = useState<any[]>([]);
    const [matterQuery, setMatterQuery] = useState('');
    const [showMatterDropdown, setShowMatterDropdown] = useState(false);
    const [timeEntries, setTimeEntries] = useState<any[]>([]);
    const [expenses, setExpenses] = useState<any[]>([]);
    const [loadingItems, setLoadingItems] = useState(false);
    const [errors, setErrors] = useState<Record<string, string[]>>({});
    const [submitting, setSubmitting] = useState(false);

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

    useEffect(() => {
        if (!form.client_matter_id) {
            setTimeEntries([]);
            setExpenses([]);
            return;
        }
        fetchEligibleItems(Number(form.client_matter_id));
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [form.client_matter_id]);

    async function fetchMatters() {
        try {
            const res = await makeGetRequest('/api/matters?per_page=200', {token});
            const payload = res.data?.result ?? res.data ?? {};
            const list = payload?.data ?? payload ?? [];
            setMatters(Array.isArray(list) ? list : []);
        } catch {
            notify.toastErrorMessage('Failed to load matters');
        }
    }

    async function fetchEligibleItems(matterId: number) {
        setLoadingItems(true);
        try {
            const params = new URLSearchParams({client_matter_id: String(matterId)});
            const res = await makeGetRequest(`/api/invoices/eligible-items?${params}`, {token});
            const payload = res.data?.result ?? res.data ?? {};
            setTimeEntries(Array.isArray(payload.time_entries) ? payload.time_entries : []);
            setExpenses(Array.isArray(payload.expenses) ? payload.expenses : []);
            setForm(f => ({...f, time_entry_ids: [], expense_ids: []}));
        } catch (e: any) {
            notify.toastErrorMessage(e?.response?.data?.message || 'Failed to load invoice items');
        } finally {
            setLoadingItems(false);
        }
    }

    const filteredMatters = useMemo(() => {
        const needle = matterQuery.trim().toLowerCase();
        if (!needle) return matters.slice(0, 50);
        return matters.filter((m: any) => {
            const ref = (m.reference_number ?? '').toLowerCase();
            const type = (m.matter_type ?? '').toLowerCase();
            const client = (m.client?.name ?? '').toLowerCase();
            return ref.includes(needle) || type.includes(needle) || client.includes(needle);
        }).slice(0, 50);
    }, [matters, matterQuery]);

    const totals = useMemo(() => {
        const timeSubtotal = timeEntries
            .filter(entry => form.time_entry_ids.includes(entry.id))
            .reduce((sum, entry) => sum + (Number(entry.duration_minutes ?? 0) / 60) * Number(entry.hourly_rate ?? 0), 0);
        const expenseSubtotal = expenses
            .filter(expense => form.expense_ids.includes(expense.id))
            .reduce((sum, expense) => sum + Number(expense.amount ?? 0), 0);
        const subtotal = timeSubtotal + expenseSubtotal;
        const tax = subtotal * (Number(form.tax_rate || 0) / 100);
        return {timeSubtotal, expenseSubtotal, subtotal, tax, total: subtotal + tax};
    }, [timeEntries, expenses, form.time_entry_ids, form.expense_ids, form.tax_rate]);

    const toggleId = (key: 'time_entry_ids' | 'expense_ids', id: number) => {
        setForm(f => ({
            ...f,
            [key]: f[key].includes(id) ? f[key].filter(itemId => itemId !== id) : [...f[key], id],
        }));
    };

    const submit = async (e: React.FormEvent) => {
        e.preventDefault();
        setErrors({});
        const validation: Record<string, string[]> = {};
        if (!form.client_matter_id) validation.client_matter_id = ['Matter is required'];
        if (!form.due_date) validation.due_date = ['Due date is required'];
        if (form.time_entry_ids.length === 0 && form.expense_ids.length === 0) validation.items = ['Select at least one approved time entry or expense'];
        if (Object.keys(validation).length) {
            setErrors(validation);
            return;
        }

        setSubmitting(true);
        try {
            await makePostRequest('/api/invoices', {
                client_profile_id: form.client_profile_id,
                client_matter_id: form.client_matter_id,
                issued_date: form.issued_date,
                due_date: form.due_date,
                tax_rate: Number(form.tax_rate || 0),
                notes: form.notes.trim() || null,
                payment_instructions: form.payment_instructions.trim() || null,
                time_entry_ids: form.time_entry_ids,
                expense_ids: form.expense_ids,
            }, {token});
            notify.toastSuccessMessage('Invoice created');
            router.visit('/invoices');
        } catch (err: any) {
            if (err?.response?.data?.errors) setErrors(err.response.data.errors);
            else notify.toastErrorMessage(err?.response?.data?.message || 'Failed to create invoice');
        } finally {
            setSubmitting(false);
        }
    };

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

            <form onSubmit={submit} noValidate className="grid grid-cols-12 gap-6">
                <div className="col-span-12 lg:col-span-8">
                    <div className="box"><div className="box-body space-y-5">
                        <div className="relative">
                            <label className="ti-form-label">Matter</label>
                            <input type="text" className="ti-form-input" placeholder="Search matter by reference, type, or client" value={matterQuery} onChange={e => { setMatterQuery(e.target.value); setShowMatterDropdown(true); setForm(f => ({...f, client_profile_id: '', client_matter_id: ''})); }} onFocus={() => setShowMatterDropdown(true)} onBlur={() => setTimeout(() => setShowMatterDropdown(false), 150)} />
                            {showMatterDropdown && <ul className="absolute z-20 left-0 right-0 bg-white border rounded mt-1 max-h-56 overflow-auto shadow">
                                {filteredMatters.length === 0 && <li className="px-3 py-2 text-sm text-gray-500">No matters found</li>}
                                {filteredMatters.map((m: any) => <li key={m.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: m.client_profile_id, client_matter_id: m.id})); setMatterQuery(`${m.reference_number ?? ''} - ${m.matter_type ?? ''}${m.client?.name ? ` (${m.client.name})` : ''}`); setShowMatterDropdown(false); }}><div className="font-medium">{m.reference_number} - {m.matter_type}</div>{m.client?.name && <div className="text-xs text-gray-500">{m.client.name}</div>}</li>)}
                            </ul>}
                            {errors.client_matter_id && <p className="text-sm text-red-600 mt-1">{errors.client_matter_id[0]}</p>}
                        </div>

                        <div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
                            <div><label className="ti-form-label">Issued date</label><input type="date" className="ti-form-input" value={form.issued_date} onChange={e => setForm(f => ({...f, issued_date: e.target.value}))} /></div>
                            <div><label className="ti-form-label">Due date</label><input type="date" className="ti-form-input" value={form.due_date} onChange={e => setForm(f => ({...f, due_date: e.target.value}))} />{errors.due_date && <p className="text-sm text-red-600 mt-1">{errors.due_date[0]}</p>}</div>
                            <div><label className="ti-form-label">Tax rate (%)</label><input type="number" step="0.01" min="0" className="ti-form-input" value={form.tax_rate} onChange={e => setForm(f => ({...f, tax_rate: e.target.value === '' ? '' : Number(e.target.value)}))} /></div>
                        </div>
                    </div></div>

                    <InvoiceItems title="Approved Time Entries" loading={loadingItems} emptyText="No approved billable time entries for this matter." colSpan={6}>
                        {timeEntries.map(entry => {
                            const amount = (Number(entry.duration_minutes ?? 0) / 60) * Number(entry.hourly_rate ?? 0);
                            return <tr key={entry.id}><td><input type="checkbox" checked={form.time_entry_ids.includes(entry.id)} onChange={() => toggleId('time_entry_ids', entry.id)} /></td><td>{dateLabel(entry.entry_date)}</td><td className="max-w-xs truncate">{entry.description}</td><td>{entry.user?.name ?? '-'}</td><td>{hours(entry.duration_minutes)}</td><td>{money(amount)}</td></tr>;
                        })}
                    </InvoiceItems>

                    <InvoiceItems title="Approved Expenses" loading={loadingItems} emptyText="No approved billable expenses for this matter." colSpan={6}>
                        {expenses.map(expense => <tr key={expense.id}><td><input type="checkbox" checked={form.expense_ids.includes(expense.id)} onChange={() => toggleId('expense_ids', expense.id)} /></td><td>{dateLabel(expense.expense_date)}</td><td className="max-w-xs truncate">{expense.description}</td><td>{expense.expense_type ?? '-'}</td><td>1</td><td>{money(expense.amount)}</td></tr>)}
                    </InvoiceItems>
                    {errors.items && <p className="text-sm text-red-600 mt-2">{errors.items[0]}</p>}
                </div>

                <div className="col-span-12 lg:col-span-4">
                    <div className="box sticky top-6"><div className="box-body space-y-5">
                        <h3 className="text-base font-semibold">Invoice Summary</h3>
                        <div className="space-y-2 text-sm"><div className="flex justify-between"><span>Time</span><span>{money(totals.timeSubtotal)}</span></div><div className="flex justify-between"><span>Expenses</span><span>{money(totals.expenseSubtotal)}</span></div><div className="flex justify-between"><span>Subtotal</span><span>{money(totals.subtotal)}</span></div><div className="flex justify-between"><span>Tax</span><span>{money(totals.tax)}</span></div><div className="flex justify-between text-lg font-semibold border-t pt-2"><span>Total</span><span>{money(totals.total)}</span></div></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><label className="ti-form-label">Payment instructions</label><textarea className="ti-form-input" rows={3} value={form.payment_instructions} onChange={e => setForm(f => ({...f, payment_instructions: e.target.value}))} /></div>
                        <div className="flex justify-end gap-2 pt-2"><Link href="/invoices" className="px-4 py-2 text-sm border rounded-lg hover:bg-gray-50">Cancel</Link><button type="submit" disabled={submitting} className="ti-btn ti-btn-primary px-4 py-2">{submitting ? 'Creating...' : 'Create Invoice'}</button></div>
                    </div></div>
                </div>
            </form>
        </MainLayout>
    );
}

function InvoiceItems({title, loading, emptyText, colSpan, children}: { title: string; loading: boolean; emptyText: string; colSpan: number; children: React.ReactNode }): JSX.Element {
    const hasRows = React.Children.count(children) > 0;
    return (
        <div className="box mt-6"><div className="box-body"><h3 className="text-base font-semibold mb-4">{title}</h3><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 className="w-10"></th><th>Date</th><th>Description</th><th>Source</th><th>Qty</th><th>Amount</th></tr></thead><tbody>{loading ? <tr><td colSpan={colSpan} className="text-center py-8">Loading...</td></tr> : !hasRows ? <tr><td colSpan={colSpan} className="text-center py-8">{emptyText}</td></tr> : children}</tbody></table></div></div></div>
    );
}
