import { Form, Head, Link, router, useForm } from '@inertiajs/react';
import { Check, ClipboardCheck, PackageCheck, PackageX, Truck } from 'lucide-react';
import { EmptyState, PageHeader, SectionCard } from '@/components/crm/page-header';
import { StatusPill } from '@/components/crm/status-badge';
import { Button } from '@/components/ui/button';
import { formatDate, formatDateTime } from '@/lib/format';
import { cn } from '@/lib/utils';

/**
 * The pick list board.
 *
 * One card per job: what was asked for, what is held, what has been taken, and
 * what is left. A picker reads the line, types the quantity they found and
 * saves it; a line that comes up short needs a sentence saying why, because
 * that sentence is what the office orders against.
 */

type Line = {
    id: number;
    description: string;
    unit: string;
    required: number;
    picked: number | null;
    short: number;
    reserved: number;
    note: string | null;
    collected: boolean;
    on_shelf: number | null;
    product: { sku: string; name: string } | null;
    url: string;
};

type Pick = {
    id: number;
    reference: string;
    status: { value: string; label: string; short_label: string; tone: string };
    note: string | null;
    warehouse_note: string | null;
    requested_at: string | null;
    completed_at: string | null;
    job: {
        id: number | null;
        job_number: string | null;
        customer: string | null;
        install_scheduled_for: string | null;
        url: string | null;
    };
    requester: string | null;
    picker: string | null;
    lines: Line[];
    progress: {
        lines: number;
        recorded: number;
        required: number;
        picked: number;
        short: number;
    };
    urls: {
        assign: string;
        complete: string;
        lacking: string;
        note: string;
        dispatch: string;
        cancel: string;
    };
};

type Candidate = {
    id: number;
    job_number: string;
    customer: string | null;
    status: { value: string; label: string; tone: string };
    install_scheduled_for: string | null;
    parts: number;
    equipment: number;
};

type Props = {
    picks: Pick[];
    candidates: Candidate[];
    unscheduledCandidates: Candidate[];
    candidateCounts: { upcoming: number; unscheduled: number };
    filters: { status: string };
    stats: {
        requested: number;
        picking: number;
        lacking: number;
        picked_this_week: number;
        short_lines: number;
    };
    filterOptions: {
        statuses: Array<{ value: string; label: string; tone?: string }>;
    };
    urls: { store: string; index: string };
    can: { manage: boolean };
};

const numberInput =
    'border-input dark:bg-input/30 h-9 w-20 rounded-md border bg-transparent px-2 text-sm tabular-nums shadow-xs outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]';

function Stat({ label, value, tone }: { label: string; value: number; tone: string }) {
    return (
        <div className="ring-hairline rounded-xl px-4 py-3 ring-1">
            <p className="text-muted-foreground text-xs">{label}</p>
            <p className={cn('crm-num mt-1 text-2xl font-semibold', tone)}>{value}</p>
        </div>
    );
}

/**
 * The warehouse's decision on one pick: a note, a shortage, or ready to leave.
 *
 * The note is deliberately kept beside the buttons rather than hidden in a
 * prompt: a shortage without the part name is useless to the office, and the
 * person holding the shelf is the only one who knows what is actually missing.
 */
function PickWarehouseActions({ pick }: { pick: Pick }) {
    const form = useForm({
        warehouse_note: pick.warehouse_note ?? '',
    });

    const open =
        pick.status.value === 'requested' ||
        pick.status.value === 'picking' ||
        pick.status.value === 'lacking';
    const everyLineRecorded = pick.progress.recorded === pick.progress.lines;
    const ready = everyLineRecorded && pick.progress.short === 0;

    const submit = (url: string) => {
        form.post(url, { preserveScroll: true });
    };

    // These three actions return different validation keys, so read them from
    // the shared errors bag rather than assuming the form only has one field.
    const errors = form.errors as Record<string, string | undefined>;

    return (
        <div className="bg-muted/20 ring-hairline mt-4 rounded-lg p-3 ring-1">
            <label
                htmlFor={`warehouse-note-${pick.id}`}
                className="text-xs font-medium"
            >
                Warehouse note
            </label>
            <textarea
                id={`warehouse-note-${pick.id}`}
                value={form.data.warehouse_note}
                onChange={(event) =>
                    form.setData('warehouse_note', event.target.value)
                }
                maxLength={1000}
                placeholder="What is missing, on order, or worth telling the office?"
                className="border-input dark:bg-input/30 mt-1.5 min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-sm leading-relaxed shadow-xs outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]"
            />
            {form.errors.warehouse_note ? (
                <p className="text-danger mt-1 text-xs" role="alert">
                    {form.errors.warehouse_note}
                </p>
            ) : null}

            <div className="mt-2 flex flex-wrap items-center gap-2">
                <Button
                    type="button"
                    size="sm"
                    variant="outline"
                    disabled={form.processing}
                    onClick={() => submit(pick.urls.note)}
                >
                    Save note
                </Button>

                {open ? (
                    <>
                        <Button
                            type="button"
                            size="sm"
                            variant="outline"
                            className="text-danger hover:text-danger"
                            disabled={
                                form.processing ||
                                form.data.warehouse_note.trim() === ''
                            }
                            onClick={() => submit(pick.urls.lacking)}
                        >
                            <PackageX />
                            Lacking components
                        </Button>

                        <Button
                            type="button"
                            size="sm"
                            disabled={form.processing || !ready}
                            title={
                                ready
                                    ? 'Everything is picked and ready to leave'
                                    : 'Record every line in full before marking ready'
                            }
                            onClick={() => submit(pick.urls.complete)}
                        >
                            <PackageCheck />
                            Ready to deliver
                        </Button>
                    </>
                ) : null}

                {pick.status.value === 'picked' ? (
                    <Button
                        type="button"
                        size="sm"
                        variant="outline"
                        disabled={form.processing}
                        onClick={() =>
                            router.post(pick.urls.dispatch, {}, { preserveScroll: true })
                        }
                    >
                        <Truck />
                        Mark collected / dispatched
                    </Button>
                ) : null}
            </div>

            {errors.picked ? (
                <p className="text-danger mt-2 text-xs" role="alert">
                    {errors.picked}
                </p>
            ) : null}
            {errors.quantity ? (
                <p className="text-danger mt-2 text-xs" role="alert">
                    {errors.quantity}
                </p>
            ) : null}
            {errors.pick ? (
                <p className="text-danger mt-2 text-xs" role="alert">
                    {errors.pick}
                </p>
            ) : null}
            {errors.dispatch ? (
                <p className="text-danger mt-2 text-xs" role="alert">
                    {errors.dispatch}
                </p>
            ) : null}
        </div>
    );
}

function CandidateQueue({
    title,
    candidates,
    total,
    storeUrl,
}: {
    title: string;
    candidates: Candidate[];
    total: number;
    storeUrl: string;
}) {
    if (candidates.length === 0) {
        return null;
    }

    return (
        <div>
            <div className="flex flex-wrap items-baseline justify-between gap-2">
                <h3 className="text-sm font-semibold">{title}</h3>
                <span className="text-muted-foreground text-xs">
                    {total > candidates.length
                        ? `Showing ${candidates.length} of ${total}`
                        : `${total} ${total === 1 ? 'job' : 'jobs'}`}
                </span>
            </div>

            <div className="divide-y divide-hairline">
                {candidates.map((candidate) => (
                    <div
                        key={candidate.id}
                        className="flex flex-col gap-3 py-3 first:pt-0 last:pb-0 sm:flex-row sm:items-center sm:justify-between"
                    >
                        <div className="min-w-0">
                            <div className="flex flex-wrap items-center gap-2">
                                <span className="text-sm font-medium">
                                    {candidate.job_number}
                                </span>
                                <StatusPill tone={candidate.status.tone}>
                                    {candidate.status.label}
                                </StatusPill>
                                {candidate.install_scheduled_for ? (
                                    <span className="text-xs text-muted-foreground">
                                        Install {formatDate(candidate.install_scheduled_for)}
                                    </span>
                                ) : (
                                    <span className="text-xs font-medium text-amber-600 dark:text-amber-400">
                                        No install date yet
                                    </span>
                                )}
                            </div>
                            <p className="mt-1 text-xs text-muted-foreground">
                                {candidate.customer ?? 'No customer'}
                                {' · '}
                                {candidate.equipment}{' '}
                                {candidate.equipment === 1 ? 'equipment line' : 'equipment lines'}
                                {' · '}
                                {candidate.parts}{' '}
                                {candidate.parts === 1 ? 'drafted part' : 'drafted parts'}
                            </p>
                        </div>
                        <Button
                            type="button"
                            size="sm"
                            variant="outline"
                            onClick={() =>
                                router.post(
                                    storeUrl,
                                    { job_id: candidate.id },
                                    { preserveScroll: true },
                                )
                            }
                        >
                            <ClipboardCheck />
                            Start pick list
                        </Button>
                    </div>
                ))}
            </div>
        </div>
    );
}

export default function WarehousePicking({
    picks,
    candidates,
    unscheduledCandidates,
    candidateCounts,
    filters,
    stats,
    filterOptions,
    urls,
    can,
}: Props) {
    return (
        <>
            <Head title="Pick lists" />

            <div className="flex flex-col gap-5">
                <PageHeader
                    title="Pick lists"
                    description="What the warehouse has been asked to gather for each job, what is held on the shelf for it, and what was actually taken."
                />

                <div className="grid grid-cols-2 gap-3 lg:grid-cols-5">
                    <Stat label="Waiting to be picked" value={stats.requested} tone="text-amber-600 dark:text-amber-400" />
                    <Stat label="Being picked" value={stats.picking} tone="text-blue-600 dark:text-blue-400" />
                    <Stat label="Lacking components" value={stats.lacking} tone={stats.lacking > 0 ? 'text-danger' : 'text-muted-foreground'} />
                    <Stat label="Ready this week" value={stats.picked_this_week} tone="text-emerald-600 dark:text-emerald-400" />
                    <Stat label="Short lines to chase" value={stats.short_lines} tone={stats.short_lines > 0 ? 'text-danger' : 'text-muted-foreground'} />
                </div>

                {can.manage ? (
                    <SectionCard
                        title="Jobs coming into the warehouse"
                        description="Jobs appear here from their own system and parts as soon as they exist. Pre-approved jobs are listed first; jobs with no install date are still included. Starting a pick holds the free stock for that job."
                        icon={Truck}
                        tone="solar"
                    >
                        {candidates.length === 0 && unscheduledCandidates.length === 0 ? (
                            <p className="text-muted-foreground text-sm">
                                Nothing is waiting for a pick list. A job appears
                                here when it has equipment or parts to gather
                                and no pick list is covering it.
                            </p>
                        ) : (
                            <div className="space-y-5">
                                <CandidateQueue
                                    title="Upcoming installs"
                                    candidates={candidates}
                                    total={candidateCounts.upcoming}
                                    storeUrl={urls.store}
                                />
                                <CandidateQueue
                                    title="No install date yet"
                                    candidates={unscheduledCandidates}
                                    total={candidateCounts.unscheduled}
                                    storeUrl={urls.store}
                                />
                            </div>
                        )}
                    </SectionCard>
                ) : null}

                <div className="flex flex-wrap gap-1.5">
                    {filterOptions.statuses.map((option) => (
                        <Link
                            key={option.value}
                            href={`${urls.index}?status=${option.value}`}
                            preserveScroll
                            className={cn(
                                'rounded-full px-3 py-1 text-xs font-medium ring-1 transition-colors',
                                filters.status === option.value
                                    ? 'bg-foreground text-background ring-foreground'
                                    : 'text-muted-foreground ring-hairline hover:bg-accent/50 hover:text-foreground',
                            )}
                        >
                            {option.label}
                        </Link>
                    ))}
                </div>

                {picks.length === 0 ? (
                    <SectionCard title="Nothing here" icon={PackageCheck} tone="slate">
                        <EmptyState
                            icon={ClipboardCheck}
                            title="No pick lists in this view"
                            description="Raise one from a job's parts list, or switch the filter to see the lists that are finished."
                        />
                    </SectionCard>
                ) : (
                    <div className="flex flex-col gap-4">
                        {picks.map((pick) => (
                            <SectionCard
                                key={pick.id}
                                title={`${pick.reference} · ${pick.job.job_number ?? 'Job removed'}`}
                                description={[
                                    pick.job.customer,
                                    pick.job.install_scheduled_for
                                        ? `install ${formatDate(pick.job.install_scheduled_for)}`
                                        : 'no install date',
                                    pick.picker ? `picked by ${pick.picker}` : 'unassigned',
                                    pick.requested_at ? `raised ${formatDateTime(pick.requested_at)}` : null,
                                    pick.note ? `request: ${pick.note}` : null,
                                ]
                                    .filter(Boolean)
                                    .join(' · ')}
                                icon={ClipboardCheck}
                                tone="slate"
                                actions={
                                    <div className="flex flex-wrap items-center gap-2">
                                        <StatusPill tone={pick.status.tone}>{pick.status.label}</StatusPill>

                                        {pick.progress.short > 0 ? (
                                            <StatusPill tone="danger">
                                                {pick.progress.short} {pick.progress.short === 1 ? 'unit' : 'units'} short
                                            </StatusPill>
                                        ) : null}
                                    </div>
                                }
                            >
                                <div className="overflow-x-auto">
                                    <table className="w-full text-sm">
                                        <thead>
                                            <tr className="text-muted-foreground border-hairline border-b text-left text-xs">
                                                <th className="py-2 pr-3 font-medium">Part</th>
                                                <th className="py-2 pr-3 text-right font-medium">Needed</th>
                                                <th className="py-2 pr-3 text-right font-medium">Held</th>
                                                <th className="py-2 pr-3 text-right font-medium">On shelf</th>
                                                <th className="py-2 pr-3 font-medium">Collected</th>
                                            </tr>
                                        </thead>
                                        <tbody>
                                            {pick.lines.map((line) => (
                                                <tr key={line.id} className="border-hairline border-b last:border-0">
                                                    <td className="py-2.5 pr-3">
                                                        <p className="font-medium">{line.description}</p>
                                                        <p className="text-muted-foreground text-xs">
                                                            {line.product ? `${line.product.sku} · ${line.product.name}` : 'Not linked to a catalogue line'}
                                                            {line.note ? ` · ${line.note}` : ''}
                                                        </p>
                                                    </td>
                                                    <td className="py-2.5 pr-3 text-right tabular-nums">
                                                        {line.required} {line.unit}
                                                    </td>
                                                    <td className="py-2.5 pr-3 text-right tabular-nums text-muted-foreground">
                                                        {line.reserved}
                                                    </td>
                                                    <td className="py-2.5 pr-3 text-right tabular-nums text-muted-foreground">
                                                        {line.on_shelf ?? '—'}
                                                    </td>
                                                    <td className="py-2.5 pr-3">
                                                        {can.manage && (pick.status.value === 'requested' || pick.status.value === 'picking' || pick.status.value === 'lacking') ? (
                                                            <div className="flex flex-wrap items-center gap-2">
                                                                <button
                                                                    type="button"
                                                                    disabled={line.collected}
                                                                    aria-pressed={line.collected}
                                                                    aria-label={
                                                                        line.collected
                                                                            ? `${line.description} is collected`
                                                                            : `Mark ${line.description} as collected`
                                                                    }
                                                                    onClick={() =>
                                                                        router.patch(
                                                                            line.url,
                                                                            {
                                                                                picked_quantity: line.required,
                                                                                note: null,
                                                                            },
                                                                            { preserveScroll: true },
                                                                        )
                                                                    }
                                                                    className={cn(
                                                                        'inline-flex h-9 items-center gap-1.5 rounded-md border px-2.5 text-xs font-medium transition-colors',
                                                                        line.collected
                                                                            ? 'border-emerald-600/30 bg-emerald-600/10 text-emerald-700 dark:text-emerald-400'
                                                                            : 'border-hairline text-muted-foreground hover:bg-accent/50 hover:text-foreground',
                                                                    )}
                                                                >
                                                                    {line.collected ? (
                                                                        <Check className="size-3.5" />
                                                                    ) : (
                                                                        <span className="size-3 rounded-sm border border-current" />
                                                                    )}
                                                                    {line.collected ? 'Collected' : 'Tick collected'}
                                                                </button>

                                                                <Form action={line.url} method="patch" className="flex flex-wrap items-center gap-2">
                                                                    {({ processing, errors }) => (
                                                                        <>
                                                                            <input
                                                                                type="number"
                                                                                name="picked_quantity"
                                                                                min="0"
                                                                                max={line.required}
                                                                                step="0.01"
                                                                                defaultValue={line.picked ?? ''}
                                                                                aria-label={`Picked quantity for ${line.description}`}
                                                                                className={numberInput}
                                                                            />
                                                                            <input
                                                                                type="text"
                                                                                name="note"
                                                                                defaultValue={line.note ?? ''}
                                                                                placeholder="Why short?"
                                                                                aria-label={`Note for ${line.description}`}
                                                                                className={numberInput.replace('w-20', 'w-48')}
                                                                            />
                                                                            <Button type="submit" size="sm" variant="outline" disabled={processing}>
                                                                                Save
                                                                            </Button>
                                                                            {errors.picked_quantity ? (
                                                                                <span className="text-danger text-xs">{errors.picked_quantity}</span>
                                                                            ) : null}
                                                                            {errors.note ? <span className="text-danger text-xs">{errors.note}</span> : null}
                                                                        </>
                                                                    )}
                                                                </Form>
                                                            </div>
                                                        ) : (
                                                            <span className="tabular-nums">
                                                                {line.picked === null ? '—' : `${line.picked} ${line.unit}`}
                                                                {line.short > 0 ? (
                                                                    <span className="text-danger"> ({line.short} short)</span>
                                                                ) : null}
                                                            </span>
                                                        )}
                                                    </td>
                                                </tr>
                                            ))}
                                        </tbody>
                                    </table>
                                </div>

                                <div className="mt-4 flex flex-wrap items-center justify-between gap-3">
                                    <p className="text-muted-foreground text-xs">
                                        {pick.progress.recorded} of {pick.progress.lines} lines recorded ·{' '}
                                        {pick.progress.picked} of {pick.progress.required} units collected
                                        {pick.completed_at ? ` · ready ${formatDateTime(pick.completed_at)}` : ''}
                                    </p>

                                    {can.manage ? (
                                        <div className="flex flex-wrap gap-2">
                                            {pick.status.value === 'requested' ? (
                                                <Form action={pick.urls.assign} method="patch">
                                                    {({ processing }) => (
                                                        <Button type="submit" variant="outline" size="sm" disabled={processing}>
                                                            Take this pick
                                                        </Button>
                                                    )}
                                                </Form>
                                            ) : null}

                                            {pick.status.value === 'requested' ||
                                            pick.status.value === 'picking' ||
                                            pick.status.value === 'lacking' ? (
                                                <Button
                                                    type="button"
                                                    variant="ghost"
                                                    size="sm"
                                                    onClick={() => {
                                                        if (window.confirm(`Cancel ${pick.reference} and release the stock held for it?`)) {
                                                            router.post(pick.urls.cancel, {}, { preserveScroll: true });
                                                        }
                                                    }}
                                                >
                                                    Cancel
                                                </Button>
                                            ) : null}
                                        </div>
                                    ) : null}
                                </div>

                                {can.manage ? (
                                    <PickWarehouseActions pick={pick} />
                                ) : pick.warehouse_note ? (
                                    <p className="mt-4 rounded-lg bg-muted/30 px-3 py-2 text-xs leading-relaxed text-muted-foreground">
                                        Warehouse note: {pick.warehouse_note}
                                    </p>
                                ) : null}
                            </SectionCard>
                        ))}
                    </div>
                )}
            </div>
        </>
    );
}

WarehousePicking.layout = {
    breadcrumbs: [
        { title: 'Warehouse', href: '/warehouse' },
        { title: 'Pick lists', href: '/warehouse/picking' },
    ],
};
