"use client"

import { useMemo } from "react"
import { AlertTriangle, Plus, Save } from "lucide-react"

import { Button } from "@/shared/components/ui/button"
import { Alert, AlertTitle } from "@/shared/components/ui/alert"
import { FieldGroup } from "@/shared/components/ui/field"
import {
    Rhform,
    RhfTextField,
    RhfSelectField,
    RhfTextareaField,
    RhfAsyncSelectField,
    RhfAutoGenerateField,
    RhfDateField,
} from "@/shared/components/form"
import { toast } from "sonner"
import { useAuthApi } from "@/shared/useApi"
import { useResourceForm } from "@/shared/hooks/use-resource-form"
import { useFormMutation } from "@/shared/hooks/use-form-mutation"
import { toRelation, toId, getTodayDate } from "@/shared/lib/utils"

import {
    paymentMadeFormSchema,
    type PaymentMadeFormValues,
} from "./payment-made.schema"
import {
    ApiError,
    BILL_ROUTES,
    PAYMENT_MODE_ROUTES,
    EMPLOYEE_ROUTES,
    PAYMENT_MADE_ROUTES,
    PaymentFor,
} from "@garage/api"
import { RhfVendorSelectField } from "@/modules/vendors/rhf-vendor-select-field"

// ── Constants ──

const PAYMENT_FOR_OPTIONS = PaymentFor.map((value) => ({
    value,
    label: value.charAt(0).toUpperCase() + value.slice(1),
}))

// ── Props ──

export type PaymentMadeFormProps = {
    resourceId?: string | null
    initialData?: unknown
    onSuccess?: () => void
    billId?: string | number | null
    expenseId?: string | number | null
}

// ── Default values ──

const DEFAULT_VALUES: PaymentMadeFormValues & { details: Array<{ bill_id?: string | number | null; amount_paid?: number, expense_id?: string | number | null }> } = {
    bill: null,
    vendor: null,
    employee: null,
    payment_mode: null,
    payment_for: "bill",
    amount: 0,
    payment_number: "",
    payment_reference: "",
    payment_date: getTodayDate(),
    paid_through: "",
    notes: "",
    details: [{ amount_paid: 0 }]
}

// ── Mapping helpers ──

function mapToFormValues(data: unknown): typeof DEFAULT_VALUES {
    const d = (data as any)?.data ?? data ?? {}

    // PaymentMade lists carry the linked bill/expense inside details[]; top-level
    // bill_id/expense_id only exist on inputs sent from a bill/expense subpage.
    const firstDetail = Array.isArray(d.details) ? d.details[0] ?? {} : {}
    const billId = d.bill_id ?? firstDetail.bill_id ?? firstDetail.bill?.id
    const billNumber = d.bill?.bill_number ?? d.bill_number ?? firstDetail.bill?.bill_number
    const expenseId = d.expense_id ?? firstDetail.expense_id ?? firstDetail.expense?.id

    // Resolve payment_mode label from nested object (title) or fallback to id
    const paymentModeId = d.payment_mode_id ?? d.payment_mode?.id
    const paymentModeLabel = d.payment_mode?.title ?? d.payment_mode?.name ?? d.payment_mode_name

    return {
        bill: toRelation(billId, billNumber),
        vendor: toRelation(d.vendor_id ?? d.vendor?.id, d.vendor?.company_name ?? d.vendor?.name ?? d.vendor_name),
        employee: toRelation(d.employee_id ?? d.employee?.id, d.employee?.first_name ? `${d.employee.first_name} ${d.employee.last_name ?? ""}`.trim() : d.employee_name),
        payment_mode: toRelation(paymentModeId, paymentModeLabel),
        payment_for: d.payment_for || (expenseId ? "expense" : "bill"),
        amount: d.payment_made != null ? Number(d.payment_made) : firstDetail.amount_paid != null ? Number(firstDetail.amount_paid) : 0,
        payment_number: d.payment_number || "",
        payment_reference: d.payment_reference || "",
        payment_date: d.payment_date || "",
        paid_through: d.paid_through || "",
        notes: d.notes || "",
        details: [{ bill_id: billId, expense_id: expenseId, amount_paid: firstDetail.amount_paid ?? 0 }],
    }
}


function mapFormToPayload(values: PaymentMadeFormValues, billId?: string | number | null, expenseId?: string | number | null) {
    const resolvedBillId = billId ?? toId(values.bill)
    const paymentDetails =
        values.payment_for === "expense"
            ? [{ expense_id: expenseId, amount_paid: values.amount || 0 }]
            : [{ bill_id: resolvedBillId, amount_paid: values.amount || 0 }]
    return {
        bill_id: values.payment_for === "bill" ? Number(resolvedBillId) : undefined,
        vendor_id: toId(values.vendor),
        employee_id: toId(values.employee) || undefined,
        payment_mode_id: toId(values.payment_mode),
        payment_for: values.payment_for,
        amount: values.amount || 0,
        payment_number: values.payment_number || undefined,
        payment_reference: values.payment_reference || undefined,
        payment_date: values.payment_date,
        paid_through: values.paid_through || undefined,
        notes: values.notes || undefined,
        payment_made: values.amount || 0,
        details: paymentDetails,
        ...(expenseId ? { expense_id: Number(expenseId) } : {}),
    }
}

// ── Shared mapOption for async selects ──

const mapLookupOption = (item: any) => ({
    value: String(item.id),
    label: item.name ?? item.title ?? `#${item.id}`,
})

const mapBillOption = (item: any) => ({
    value: String(item.id),
    label: item.bill_number ?? item.title ?? `#${item.id}`,
})

const mapVendorOption = (item: any) => ({
    value: String(item.id),
    label: item.name ?? item.company_name ?? `#${item.id}`,
})

const mapEmployeeOption = (item: any) => ({
    value: String(item.id),
    label: item.first_name
        ? `${item.first_name} ${item.last_name || ""}`.trim()
        : item.name ?? `#${item.id}`,
})

const STORE_OBJECT = { getOptionValue: (o: any) => o, getOptionLabel: (o: any) => o.label }

// ── Component ──

export function PaymentMadeForm({ resourceId, initialData, onSuccess, billId, expenseId }: PaymentMadeFormProps) {
    const api = useAuthApi()

    const paymentForOptions = useMemo(() => {
        if (expenseId) {
            return PAYMENT_FOR_OPTIONS.filter((option) => option.value === "expense")
        }
        return PAYMENT_FOR_OPTIONS.filter((option) => option.value === "bill")
    }, [expenseId])

    const resolvedInitialData = useMemo(() => {
        const base: any = { ...(initialData as any) }
        if (!resourceId) {
            if (billId) {
                base.payment_for = "bill"
            } else if (expenseId) {
                base.payment_for = "expense"
            } else {
                base.payment_for = "bill"
            }
        }
        return Object.keys(base).length ? base : initialData
    }, [resourceId, billId, expenseId, initialData])

    const { form, isEditing } = useResourceForm<PaymentMadeFormValues, any>({
        schema: paymentMadeFormSchema,
        defaultValues: DEFAULT_VALUES,
        resourceId,
        initialData: resolvedInitialData,
        initialize: (id) => api.paymentMades.show(id),
        queryKey: [PAYMENT_MADE_ROUTES.BY_ID, resourceId],
        mapToFormValues,
    })

    const vendor = form.watch("vendor")
    const employee = form.watch("employee")
    const paymentFor = form.watch("payment_for")
    const vendorRequired = !employee?.value
    const employeeRequired = !vendor?.value
    const showBillField = !billId && !expenseId

    const { mutate, error, isPending } = useFormMutation(form, {
        mutationFn: (values: PaymentMadeFormValues) => {
            const payload = mapFormToPayload(values, billId, expenseId)
            const promise = (isEditing && resourceId
                ? api.paymentMades.update(resourceId, payload as any)
                : api.paymentMades.create(payload as any)) as Promise<any>
            toast.promise(promise, {
                loading: isEditing ? "Updating payment..." : "Recording payment...",
                success: isEditing ? "Payment updated successfully" : "Payment recorded successfully",
                error: isEditing ? "Failed to update payment" : "Failed to record payment",
            })
            return promise
        },
        onError: (error) => {
            if (!(error instanceof ApiError) || !error.validationErrors) {
                return
            }

            // Surface the actual backend validation messages on each field
            // instead of blanket-replacing them with the "not both" message —
            // that masked unrelated errors and showed the wrong text when only
            // one of vendor/employee was selected.
            const errors = error.validationErrors
            const billError = errors.bill_id?.[0]
            const vendorError = errors.vendor_id?.[0]
            const employeeError = errors.employee_id?.[0]

            if (billError) {
                form.setError("bill", { message: billError })
            }
            if (vendorError) {
                form.setError("vendor", { message: vendorError })
            }
            if (employeeError) {
                form.setError("employee", { message: employeeError })
            }
        },
        onSuccess: () => {
            form.reset()
            onSuccess?.()
        },
    })

    return (
        <Rhform form={form} onSubmit={(values) => mutate(values)}>
            {error && (
                <Alert variant="destructive" className="mb-4">
                    <AlertTriangle className="me-2 h-4 w-4" />
                    <AlertTitle>
                        {isEditing ? "Failed to update payment" : "Failed to record payment"}
                    </AlertTitle>
                    {error.message}
                </Alert>
            )}

            <FieldGroup>
                <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
                    {showBillField && (
                        <RhfAsyncSelectField
                            name="bill"
                            label="Bill"
                            placeholder="Select bill"
                            required={paymentFor === "bill"}
                            queryKey={[BILL_ROUTES.INDEX]}
                            listFn={() => api.bills.list()}
                            mapOption={mapBillOption}
                            {...STORE_OBJECT}
                        />
                    )}
                    <RhfVendorSelectField
                        name="vendor"
                        label="Vendor"
                        required={vendorRequired}
                        description="Select a vendor, an employee, or both."
                    />
                    <RhfAsyncSelectField
                        name="employee"
                        label="Employee"
                        placeholder="Select employee"
                        required={employeeRequired}
                        description="Select a vendor, an employee, or both."
                        queryKey={[EMPLOYEE_ROUTES.INDEX]}
                        listFn={() => api.employees.list()}
                        mapOption={mapEmployeeOption}
                        {...STORE_OBJECT}
                    />
                </div>

                <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
                    <RhfSelectField
                        name="payment_for"
                        label="Payment For"
                        placeholder="Select type"
                        options={paymentForOptions}
                        required
                    />
                    <RhfTextField
                        name="amount"
                        label="Amount"
                        placeholder="0.00"
                        type="number"
                        required
                    />
                </div>

                <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
                    <RhfAutoGenerateField
                        table="payments"
                        autoFetch
                        name="payment_number"
                        label="Payment Number"
                        placeholder="PAY-001"
                    />
                    <RhfTextField
                        name="payment_reference"
                        label="Payment Reference"
                        placeholder="Reference"
                    />
                </div>

                <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
                    <RhfDateField
                        name="payment_date"
                        label="Payment Date"
                        required
                    />
                    <RhfAsyncSelectField
                        name="payment_mode"
                        label="Payment Mode"
                        placeholder="Select payment mode"
                        required
                        queryKey={[PAYMENT_MODE_ROUTES.INDEX]}
                        listFn={() => api.paymentModes.list()}
                        mapOption={mapLookupOption}
                        {...STORE_OBJECT}
                    />
                </div>

                <RhfTextField
                    name="paid_through"
                    label="Paid Through"
                    placeholder="Account name"
                />

                <RhfTextareaField
                    name="notes"
                    label="Notes"
                    rows={3}
                    placeholder="Add any notes about this payment..."
                />

                <Button type="submit" variant="default" disabled={isPending}>
                    {isEditing ? <Save /> : <Plus />}
                    {isPending
                        ? (isEditing ? "Updating..." : "Recording...")
                        : (isEditing ? "Update Payment" : "Record Payment")}
                </Button>
            </FieldGroup>
        </Rhform>
    )
}
