import { Head, Link, router } from '@inertiajs/react';
import { useState } from 'react';
import {
    AlertTriangle,
    BriefcaseBusiness,
    Package,
    Plus,
    SlidersHorizontal,
    Upload,
} from 'lucide-react';

import { EmptyState, PageHeader } from '@/components/crm/page-header';
import { JobStatusBadge, PriorityBadge, RuleFlag } from '@/components/crm/status-badge';
import { NativeSelect } from '@/components/crm/native-select';
import { toneClasses } from '@/components/crm/tone';
import {
    ActiveFilters,
    DataPagination,
    FilterBar,
    FilterField,
    SearchInput,
    TableCard,
} from '@/components/crm/toolbar';
import { Button } from '@/components/ui/button';
import {
    Table,
    TableBody,
    TableCell,
    TableHead,
    TableHeader,
    TableRow,
} from '@/components/ui/table';
import { formatCurrency, formatDate, formatDuration } from '@/lib/format';
import { cn } from '@/lib/utils';
import {
    create as jobsCreate,
    index as jobsIndex,
    show as jobShow,
} from '@/routes/jobs';
import type {
    JobSummary,
    Option,
    Paginated,
    StaffOption,
    StatusOptionGroup,
} from '@/types';

/**
 * What the page header calls the list being looked at. "Needs stock" is the
 * picking queue, and naming it is the difference between a filter and a
 * mystery.
 */
const SCOPE_LABELS: Record<string, string> = {
    active: 'Active pipeline',
    mine: 'My jobs',
    stalled: 'Stalled jobs',
    short: 'Needs stock',
    completed: 'Completed jobs',
    all: 'All pipelines',
};

type JobFilters = {
    search: string | null;
    status: string | null;
    group: string | null;
    type: string | null;
    state: string | null;
    priority: string | null;
    owner: number | null;
    scope: string | null;
};

type Props = {
    jobs: Paginated<JobSummary>;
    filters: JobFilters;
    pipeline: StatusOptionGroup[];
    filterOptions: {
        types: Option[];
        states: Option[];
        priorities: Option[];
        staff: StaffOption[];
        scopes: Option[];
    };
    can: {
        create: boolean;
        viewFinancials: boolean;
        viewCompliance: boolean;
    };
};

type FilterValues = {
    search: string;
    status: string;
    type: string;
    state: string;
    priority: string;
    owner: string;
    scope: string;
};

export default function JobsIndex({
    jobs,
    filters,
    pipeline,
    filterOptions,
    can,
}: Props) {
    const [values, setValues] = useState<FilterValues>({
        search: filters.search ?? '',
        status: filters.status ?? '',
        type: filters.type ?? '',
        state: filters.state ?? '',
        priority: filters.priority ?? '',
        owner: filters.owner === null ? '' : String(filters.owner),
        scope: filters.scope ?? 'active',
    });

    const apply = (next: FilterValues) => {
        const params: Record<string, string> = {};

        Object.entries(next).forEach(([key, value]) => {
            if (value !== '') {
                params[key] = value;
            }
        });

        router.get(jobsIndex().url, params, {
            preserveState: true,
            replace: true,
        });
    };

    const filterByStatus = (status: string) => {
        const next: FilterValues = {
            ...values,
            status: values.status === status ? '' : status,
        };

        setValues(next);
        apply(next);
    };

    const reset = () => {
        const next: FilterValues = {
            search: '',
            status: '',
            type: '',
            state: '',
            priority: '',
            owner: '',
            scope: 'active',
        };

        setValues(next);
        apply(next);
    };

    const clearValue = (patch: Partial<FilterValues>) => {
        const next: FilterValues = { ...values, ...patch };

        setValues(next);
        apply(next);
    };

    const labelFor = (options: Option[], value: string): string =>
        options.find((option) => option.value === value)?.label ?? value;

    const statusLabelFor = (value: string): string =>
        pipeline
            .flatMap((group) => group.statuses)
            .find((status) => status.value === value)?.label ?? value;

    const activeFilters: Array<{
        key: string;
        label: string;
        value: string;
        onRemove: () => void;
    }> = [
        {
            key: 'search',
            label: 'Search',
            value: values.search,
            onRemove: () => clearValue({ search: '' }),
        },
        {
            key: 'status',
            label: 'Stage',
            value: values.status ? statusLabelFor(values.status) : '',
            onRemove: () => clearValue({ status: '' }),
        },
        {
            key: 'type',
            label: 'Type',
            value: values.type
                ? labelFor(filterOptions.types, values.type)
                : '',
            onRemove: () => clearValue({ type: '' }),
        },
        {
            key: 'state',
            label: 'State',
            value: values.state
                ? labelFor(filterOptions.states, values.state)
                : '',
            onRemove: () => clearValue({ state: '' }),
        },
        {
            key: 'priority',
            label: 'Priority',
            value: values.priority
                ? labelFor(filterOptions.priorities, values.priority)
                : '',
            onRemove: () => clearValue({ priority: '' }),
        },
        {
            key: 'owner',
            label: 'Assigned',
            value: values.owner
                ? labelFor(
                      filterOptions.staff.map((member) => ({
                          value: String(member.value),
                          label: member.label,
                      })),
                      values.owner,
                  )
                : '',
            onRemove: () => clearValue({ owner: '' }),
        },
    ].filter((filter) => filter.value !== '');

    const hasJobs = jobs.data.length > 0;

    return (
        <>
            <Head title="Jobs" />

            <PageHeader
                eyebrow={
                    <>
                        <BriefcaseBusiness className="size-3.5 text-solar" />
                        <span>
                            {jobs.total} {jobs.total === 1 ? 'job' : 'jobs'} in
                            view
                        </span>
                        <span aria-hidden className="text-muted-foreground/50">
                            ·
                        </span>
                        <span>
                            {SCOPE_LABELS[values.scope] ?? 'All pipelines'}
                        </span>
                    </>
                }
                title="Jobs"
                description="Every installation from enquiry through grid connection and STC closeout."
                actions={
                    can.create ? (
                        <>
                            <Button size="sm" variant="outline" asChild>
                                <Link href="/jobs/import">
                                    <Upload className="size-4" />
                                    Import
                                </Link>
                            </Button>
                            <Button size="sm" asChild>
                                <Link href={jobsCreate()}>
                                    <Plus className="size-4" />
                                    New job
                                </Link>
                            </Button>
                        </>
                    ) : null
                }
            />

            <PipelineStrip
                pipeline={pipeline}
                activeStatus={values.status}
                onSelect={filterByStatus}
            />

            <form
                onSubmit={(event) => {
                    event.preventDefault();
                    apply(values);
                }}
                className="flex flex-col gap-3"
            >
                <FilterBar
                    actions={
                        <>
                            <Button type="submit" size="sm">
                                Apply
                            </Button>
                            <Button
                                type="button"
                                size="sm"
                                variant="ghost"
                                onClick={reset}
                            >
                                Clear
                            </Button>
                        </>
                    }
                >
                    <SearchInput
                        value={values.search}
                        onChange={(search) =>
                            setValues({ ...values, search })
                        }
                        placeholder="Job number, customer, address, NMI or serial"
                        className="min-w-[16rem]"
                    />

                    <FilterField label="Stage" className="w-44">
                        <NativeSelect
                            value={values.status}
                            onChange={(event) =>
                                setValues({
                                    ...values,
                                    status: event.target.value,
                                })
                            }
                        >
                            <option value="">All stages</option>
                            {pipeline.map((group) => (
                                <optgroup
                                    key={group.group}
                                    label={group.group_label}
                                >
                                    {group.statuses.map((status) => (
                                        <option
                                            key={status.value}
                                            value={status.value}
                                        >
                                            {status.label}
                                        </option>
                                    ))}
                                </optgroup>
                            ))}
                        </NativeSelect>
                    </FilterField>

                    <FilterField label="Pipeline" className="w-40">
                        <NativeSelect
                            value={values.scope}
                            onChange={(event) =>
                                setValues({
                                    ...values,
                                    scope: event.target.value,
                                })
                            }
                        >
                            {filterOptions.scopes.map((scope) => (
                                <option key={scope.value} value={scope.value}>
                                    {scope.label}
                                </option>
                            ))}
                        </NativeSelect>
                    </FilterField>

                    <FilterField label="Type" className="w-36">
                        <NativeSelect
                            value={values.type}
                            onChange={(event) =>
                                setValues({
                                    ...values,
                                    type: event.target.value,
                                })
                            }
                        >
                            <option value="">All types</option>
                            {filterOptions.types.map((type) => (
                                <option key={type.value} value={type.value}>
                                    {type.label}
                                </option>
                            ))}
                        </NativeSelect>
                    </FilterField>

                    <FilterField label="State" className="w-36">
                        <NativeSelect
                            value={values.state}
                            onChange={(event) =>
                                setValues({
                                    ...values,
                                    state: event.target.value,
                                })
                            }
                        >
                            <option value="">All states</option>
                            {filterOptions.states.map((state) => (
                                <option key={state.value} value={state.value}>
                                    {state.label}
                                </option>
                            ))}
                        </NativeSelect>
                    </FilterField>

                    <FilterField label="Priority" className="w-32">
                        <NativeSelect
                            value={values.priority}
                            onChange={(event) =>
                                setValues({
                                    ...values,
                                    priority: event.target.value,
                                })
                            }
                        >
                            <option value="">Any</option>
                            {filterOptions.priorities.map((priority) => (
                                <option
                                    key={priority.value}
                                    value={priority.value}
                                >
                                    {priority.label}
                                </option>
                            ))}
                        </NativeSelect>
                    </FilterField>

                    <FilterField label="Assigned to" className="w-44">
                        <NativeSelect
                            value={values.owner}
                            onChange={(event) =>
                                setValues({
                                    ...values,
                                    owner: event.target.value,
                                })
                            }
                        >
                            <option value="">Anyone</option>
                            {filterOptions.staff.map((member) => (
                                <option
                                    key={member.value}
                                    value={String(member.value)}
                                >
                                    {member.label}
                                    {member.role ? ` — ${member.role}` : ''}
                                </option>
                            ))}
                        </NativeSelect>
                    </FilterField>
                </FilterBar>

                <ActiveFilters filters={activeFilters} onClear={reset} />
            </form>

            {hasJobs ? (
                <TableCard>
                    <Table>
                        <TableHeader>
                            <TableRow className="hover:bg-transparent">
                                <TableHead className="bg-surface/60 text-[11px] font-semibold tracking-wide uppercase">
                                    Job
                                </TableHead>
                                <TableHead className="bg-surface/60 text-[11px] font-semibold tracking-wide uppercase">
                                    Customer
                                </TableHead>
                                <TableHead className="bg-surface/60 text-[11px] font-semibold tracking-wide uppercase">
                                    Site
                                </TableHead>
                                <TableHead className="bg-surface/60 text-[11px] font-semibold tracking-wide uppercase">
                                    Status
                                </TableHead>
                                <TableHead className="bg-surface/60 text-[11px] font-semibold tracking-wide uppercase">
                                    Install
                                </TableHead>
                                <TableHead className="bg-surface/60 text-[11px] font-semibold tracking-wide uppercase">
                                    In stage
                                </TableHead>
                                <TableHead className="bg-surface/60 text-[11px] font-semibold tracking-wide uppercase">
                                    Waiting on
                                </TableHead>
                                <TableHead className="bg-surface/60 text-[11px] font-semibold tracking-wide uppercase">
                                    Owner
                                </TableHead>
                                {can.viewFinancials ? (
                                    <TableHead className="bg-surface/60 text-right text-[11px] font-semibold tracking-wide uppercase">
                                        Value
                                    </TableHead>
                                ) : null}
                            </TableRow>
                        </TableHeader>
                        <TableBody>
                            {jobs.data.map((job) => (
                                <TableRow
                                    key={job.id}
                                    className="group relative"
                                >
                                    <TableCell className="relative">
                                        {job.is_stalled ? (
                                            <span
                                                aria-hidden
                                                className="absolute inset-y-1 left-0 w-0.5 rounded-full bg-warning"
                                            />
                                        ) : null}
                                        <Link
                                            href={jobShow(job.id).url}
                                            className="font-mono text-xs font-medium hover:underline"
                                        >
                                            {job.job_number}
                                        </Link>
                                        <div className="text-muted-foreground mt-0.5 max-w-[16rem] truncate text-xs">
                                            {job.title ?? job.type.label}
                                        </div>
                                        <EquipmentLine job={job} />
                                    </TableCell>
                                    <TableCell>
                                        <div className="max-w-[14rem] truncate text-sm">
                                            {job.customer?.name ?? '—'}
                                        </div>
                                        <div className="text-muted-foreground text-xs">
                                            {job.customer?.phone ??
                                                job.customer
                                                    ?.customer_number ??
                                                '—'}
                                        </div>
                                    </TableCell>
                                    <TableCell>
                                        <div className="max-w-[16rem] truncate text-sm">
                                            {job.site?.address ?? '—'}
                                        </div>
                                        <div className="text-muted-foreground text-xs">
                                            {job.site?.distribution_network
                                                ? `${job.site.distribution_network} — `
                                                : ''}
                                            {job.site?.state ?? '—'}
                                        </div>
                                    </TableCell>
                                    <TableCell>
                                        <JobStatusBadge status={job.status} />
                                        <div className="mt-1.5 flex flex-wrap items-center gap-1.5">
                                            {job.priority.value !==
                                            'normal' ? (
                                                <PriorityBadge
                                                    priority={job.priority}
                                                />
                                            ) : null}
                                            {job.requires_inspection ? (
                                                <RuleFlag tone="slate">
                                                    Inspection required
                                                </RuleFlag>
                                            ) : null}
                                        </div>
                                    </TableCell>
                                    <TableCell className="whitespace-nowrap text-sm">
                                        {formatDate(
                                            job.install_scheduled_for,
                                        )}
                                    </TableCell>
                                    <TableCell className="whitespace-nowrap">
                                        <span
                                            className={cn(
                                                'crm-num text-sm',
                                                job.is_stalled
                                                    ? 'text-warning font-medium'
                                                    : 'text-muted-foreground',
                                            )}
                                        >
                                            {formatDuration(
                                                job.days_in_status,
                                            )}
                                        </span>
                                    </TableCell>
                                    <TableCell className="text-muted-foreground max-w-[12rem] truncate text-xs">
                                        {job.status.waiting_on}
                                    </TableCell>
                                    <TableCell className="max-w-[10rem] truncate text-sm">
                                        {job.owner?.name ?? '—'}
                                    </TableCell>
                                    {can.viewFinancials ? (
                                        <TableCell className="crm-num text-right text-sm">
                                            {formatCurrency(
                                                job.contract_value,
                                            )}
                                        </TableCell>
                                    ) : null}
                                </TableRow>
                            ))}
                        </TableBody>
                    </Table>

                    <DataPagination page={jobs} noun="jobs" />
                </TableCard>
            ) : (
                <div className="bg-card shadow-card rounded-xl py-6 ring-1 ring-hairline">
                    <EmptyState
                        icon={SlidersHorizontal}
                        title="No jobs match these filters"
                        description="Try clearing the filters, or create a new job for a customer."
                        action={
                            can.create ? (
                                <Button size="sm" asChild>
                                    <Link href={jobsCreate()}>
                                        <Plus className="size-4" />
                                        New job
                                    </Link>
                                </Button>
                            ) : null
                        }
                    />
                </div>
            )}
        </>
    );
}

/**
 * The design the job carries, against what the warehouse holds.
 *
 * The line under the job number is the equipment the job was sold, written from
 * the job's own fields, so a list of twenty jobs can be read for what is on
 * each roof without opening any of them. Where the equipment is also a
 * warehouse line, the stock position is shown against the quantity the job
 * needs: a shortfall is the thing that stops an install, and it is better seen
 * in the list than found on the morning of the job.
 */
function EquipmentLine({ job }: { job: JobSummary }) {
    const { equipment } = job;

    if (equipment.lines.length === 0) {
        return null;
    }

    const short = equipment.lines.filter((line) => line.shortfall !== null);
    const summary =
        equipment.summary ??
        equipment.lines
            .map((line) => line.name)
            .filter(Boolean)
            .join(' · ');

    return (
        <div className="mt-1 flex max-w-[17rem] flex-wrap items-center gap-1.5">
            <span
                className="text-muted-foreground inline-flex min-w-0 items-center gap-1 text-[11px]"
                title={equipment.lines
                    .map((line) =>
                        [
                            line.label,
                            line.name,
                            line.product?.sku,
                            line.product
                                ? `${line.product.available} in stock`
                                : 'not linked to the catalogue',
                        ]
                            .filter(Boolean)
                            .join(' · '),
                    )
                    .join('\n')}
            >
                <Package aria-hidden className="size-3 shrink-0" />
                <span className="truncate">{summary}</span>
            </span>
            {short.length > 0 ? (
                <span
                    className="inline-flex shrink-0 items-center gap-1 rounded bg-amber-100 px-1.5 py-0.5 text-[10px] font-medium text-amber-900 dark:bg-amber-500/20 dark:text-amber-200"
                    title={short
                        .map(
                            (line) =>
                                `${line.label}: needs ${line.needed ?? '?'}, ${line.product?.available ?? 0} available at ${line.product?.sku ?? 'no catalogue line'}`,
                        )
                        .join('\n')}
                >
                    <AlertTriangle aria-hidden className="size-3" />
                    Stock short {short.length}
                </span>
            ) : null}
        </div>
    );
}

/**
 * The installation pipeline as colour-coded stage chips, grouped by phase.
 * Selecting one filters the table to that status. Per-stage counts are not sent
 * to this page, so each chip carries its stage colour and nothing more.
 */
function PipelineStrip({
    pipeline,
    activeStatus,
    onSelect,
}: {
    pipeline: StatusOptionGroup[];
    activeStatus: string;
    onSelect: (status: string) => void;
}) {
    return (
        <div className="bg-card shadow-card crm-scroll flex gap-2 overflow-x-auto rounded-xl px-3 py-2.5 ring-1 ring-hairline">
            {pipeline.map((group) => {
                const groupColor = group.statuses[0]?.color ?? 'slate';
                const isGroupActive = group.statuses.some(
                    (status) => status.value === activeStatus,
                );

                return (
                    <div
                        key={group.group}
                        className="flex shrink-0 items-center gap-1.5 rounded-lg px-1.5 py-1"
                    >
                        <span className="flex items-center gap-1.5 pr-1">
                            <span
                                aria-hidden
                                className={cn(
                                    'size-1.5 rounded-full',
                                    toneClasses(groupColor).dot,
                                )}
                            />
                            <span
                                className={cn(
                                    'text-[10px] font-semibold tracking-wide uppercase',
                                    isGroupActive
                                        ? 'text-foreground'
                                        : 'text-muted-foreground',
                                )}
                            >
                                {group.group_label}
                            </span>
                        </span>

                        {group.statuses.map((stage) => {
                            const isActive = activeStatus === stage.value;
                            const classes = toneClasses(stage.color);

                            return (
                                <button
                                    key={stage.value}
                                    type="button"
                                    onClick={() => onSelect(stage.value)}
                                    title={stage.description}
                                    className={cn(
                                        'rounded-md px-2 py-1 text-xs whitespace-nowrap transition-colors',
                                        isActive
                                            ? classes.pill
                                            : 'text-muted-foreground hover:bg-accent hover:text-accent-foreground',
                                    )}
                                >
                                    {stage.label}
                                </button>
                            );
                        })}

                        <span
                            aria-hidden
                            className="bg-hairline ml-1 h-5 w-px shrink-0 last:hidden"
                        />
                    </div>
                );
            })}
        </div>
    );
}

JobsIndex.layout = {
    breadcrumbs: [
        {
            title: 'Jobs',
            href: jobsIndex(),
        },
    ],
};
