import { Head, Link, router } from '@inertiajs/react';
import { useEffect, useRef, useState } from 'react';
import {
    Activity,
    AlertTriangle,
    CheckCircle2,
    LifeBuoy,
    Plus,
    RotateCcw,
    ShieldCheck,
    Ticket,
    UserRound,
    Wrench,
} from 'lucide-react';
import { KpiTile } from '@/components/crm/kpi-tile';
import { NativeSelect } from '@/components/crm/native-select';
import { EmptyState, PageHeader } from '@/components/crm/page-header';
import {
    PriorityBadge,
    StatusDot,
    StatusLabel,
    toneClassName,
} from '@/components/crm/status-badge';
import { TicketStatusOptions } from '@/components/crm/ticket-status-options';
import {
    ActiveFilters,
    DataPagination,
    FilterBar,
    FilterField,
    SearchInput,
    SegmentedControl,
    TableCard,
} from '@/components/crm/toolbar';
import { Button } from '@/components/ui/button';
import {
    Table,
    TableBody,
    TableCell,
    TableHead,
    TableHeader,
    TableRow,
} from '@/components/ui/table';
import { formatDate, formatDuration, formatNumber } from '@/lib/format';
import { cn } from '@/lib/utils';
import { show as customerShow } from '@/routes/customers';
import { show as jobShow } from '@/routes/jobs';
import {
    create as ticketsCreate,
    index as ticketsIndex,
    show as ticketShow,
} from '@/routes/tickets';
import type { Option, TicketIndexProps } from '@/types';

type FilterValues = {
    search: string;
    status: string;
    priority: string;
    category: string;
    installer: string;
    scope: string;
};

/**
 * The support desk. Tickets arrive from the SMS system, so the list is ordered
 * the way a desk works it: most urgent first, then oldest, and every row says
 * who it belongs to, which job it is about and who installed that job.
 */
export default function TicketsIndex({
    tickets,
    filters,
    summary,
    filterOptions,
    can,
}: TicketIndexProps) {
    const [values, setValues] = useState<FilterValues>({
        search: filters.search ?? '',
        status: filters.status ?? '',
        priority: filters.priority ?? '',
        category: filters.category ?? '',
        installer: filters.installer === null ? '' : String(filters.installer),
        scope: filters.scope ?? 'open',
    });

    // Typing re-queries once the user stops, so search feels live without a
    // request per keystroke. The timer is cleared whenever another filter lands.
    const searchTimer = useRef<number | null>(null);

    const cancelPendingSearch = () => {
        if (searchTimer.current !== null) {
            window.clearTimeout(searchTimer.current);
            searchTimer.current = null;
        }
    };

    useEffect(() => cancelPendingSearch, []);

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

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

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

    const update = (patch: Partial<FilterValues>) => {
        cancelPendingSearch();

        const next: FilterValues = { ...values, ...patch };

        setValues(next);
        commit(next);
    };

    const onSearchChange = (search: string) => {
        const next: FilterValues = { ...values, search };

        setValues(next);
        cancelPendingSearch();

        searchTimer.current = window.setTimeout(() => commit(next), 350);
    };

    const reset = () => {
        const next: FilterValues = {
            search: '',
            status: '',
            priority: '',
            category: '',
            installer: '',
            scope: 'open',
        };

        cancelPendingSearch();
        setValues(next);
        commit(next);
    };

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

    const installerLabelFor = (value: string): string =>
        filterOptions.installers.find(
            (installer) => String(installer.value) === value,
        )?.label ?? value;

    // The tiles and the scope strip agree on what each narrowing means, so a
    // count and the list it opens are always the same slice of work.
    const scopeCounts: Record<string, number> = {
        active: summary.active,
        open: summary.open,
        overdue: summary.overdue,
        warranty: summary.warranty,
        all: summary.total,
    };

    const activeFilters: Array<{
        key: string;
        label: string;
        value: string;
        onRemove: () => void;
    }> = [
        {
            key: 'search',
            label: 'Search',
            value: values.search,
            onRemove: () => update({ search: '' }),
        },
        {
            key: 'status',
            label: 'Status',
            value: values.status
                ? labelFor(filterOptions.statuses, values.status)
                : '',
            onRemove: () => update({ status: '' }),
        },
        {
            key: 'priority',
            label: 'Priority',
            value: values.priority
                ? labelFor(filterOptions.priorities, values.priority)
                : '',
            onRemove: () => update({ priority: '' }),
        },
        {
            key: 'category',
            label: 'Category',
            value: values.category
                ? labelFor(filterOptions.categories, values.category)
                : '',
            onRemove: () => update({ category: '' }),
        },
        {
            key: 'installer',
            label: 'Installer',
            value: values.installer ? installerLabelFor(values.installer) : '',
            onRemove: () => update({ installer: '' }),
        },
    ];

    const hasTickets = tickets.data.length > 0;
    const hasAnyTickets = summary.total > 0;

    const ticketUrl = (params: Record<string, string>) =>
        ticketsIndex({ query: params }).url;

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

            <PageHeader
                eyebrow={
                    <>
                        <LifeBuoy className="size-3.5 text-solar-ink" />
                        <span>{formatNumber(summary.open)} open</span>
                        <span aria-hidden className="text-muted-foreground/50">
                            ·
                        </span>
                        <span
                            className={cn(
                                summary.overdue > 0 &&
                                    'font-medium text-danger',
                            )}
                        >
                            {formatNumber(summary.overdue)} past their threshold
                        </span>
                        <span aria-hidden className="text-muted-foreground/50">
                            ·
                        </span>
                        <span>
                            {formatNumber(summary.waitingOnInstaller)} waiting
                            on an installer
                        </span>
                    </>
                }
                title="Tickets"
                description="Everything reported by SMS or logged by staff, chased against the customer, the job and the installer who did the work."
                actions={
                    <>
                        <Button variant="outline" size="sm" asChild>
                            <Link href={ticketUrl({ scope: 'all' })}>
                                All tickets
                            </Link>
                        </Button>
                        {can.create ? (
                            <Button size="sm" asChild>
                                <Link href={ticketsCreate()}>
                                    <Plus className="size-4" />
                                    Log ticket
                                </Link>
                            </Button>
                        ) : null}
                    </>
                }
            />

            {/* No `auto-rows-fr` here: it forces every row to the height of the
                tallest row, so one hint that wraps to two lines paddled out
                the whole strip. Letting each row size to its own tallest tile
                keeps the cards as short as their content. */}
            <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4">
                <KpiTile
                    label="Total tickets"
                    value={formatNumber(summary.total)}
                    hint="Everything on the desk, in every state"
                    icon={Ticket}
                    tone="slate"
                    href={ticketUrl({ scope: 'all' })}
                />

                <KpiTile
                    label="Active tickets"
                    value={formatNumber(summary.active)}
                    hint="Not resolved, closed, cancelled or on hold"
                    icon={Activity}
                    tone="solar"
                    href={ticketUrl({ scope: 'active' })}
                />

                <KpiTile
                    label="Open tickets"
                    value={formatNumber(summary.open)}
                    hint="Not resolved or closed yet"
                    icon={LifeBuoy}
                    tone="info"
                    href={ticketUrl({ scope: 'open' })}
                />

                <KpiTile
                    label="Overdue"
                    value={formatNumber(summary.overdue)}
                    hint="Open longer than three days"
                    icon={AlertTriangle}
                    tone={summary.overdue > 0 ? 'danger' : 'slate'}
                    href={ticketUrl({ scope: 'overdue' })}
                />

                <KpiTile
                    label="Waiting on installer"
                    value={formatNumber(summary.waitingOnInstaller)}
                    hint="The crew who did the job owes an answer"
                    icon={Wrench}
                    tone={summary.waitingOnInstaller > 0 ? 'warning' : 'slate'}
                    href={ticketUrl({ status: 'waiting_on_installer' })}
                />

                <KpiTile
                    label="Warranty and manufacturer"
                    value={formatNumber(summary.warranty)}
                    hint="Claims with a manufacturer, waiting on parts, approved or declined"
                    icon={ShieldCheck}
                    tone={summary.warranty > 0 ? 'info' : 'slate'}
                    href={ticketUrl({ scope: 'warranty' })}
                />

                <KpiTile
                    label="No installer"
                    value={formatNumber(summary.unassigned)}
                    hint="Nobody linked who answers for the install"
                    icon={UserRound}
                    tone={summary.unassigned > 0 ? 'amber' : 'slate'}
                />

                <KpiTile
                    label="Resolved this week"
                    value={formatNumber(summary.resolvedThisWeek)}
                    hint="Closed out in the last seven days"
                    icon={CheckCircle2}
                    tone="success"
                />
            </div>

            <form
                onSubmit={(event) => {
                    event.preventDefault();
                    cancelPendingSearch();
                    commit(values);
                }}
                className="flex flex-col gap-3"
            >
                <FilterBar
                    actions={
                        <>
                            <Button type="submit" size="sm" variant="outline">
                                Search
                            </Button>
                            <Button
                                type="button"
                                size="sm"
                                variant="ghost"
                                onClick={reset}
                            >
                                <RotateCcw className="size-4" />
                                Reset
                            </Button>
                        </>
                    }
                >
                    <SearchInput
                        value={values.search}
                        onChange={onSearchChange}
                        placeholder="Ticket, issue, customer, job or phone"
                        className="min-w-[16rem]"
                    />

                    <FilterField label="Status" className="w-44">
                        <NativeSelect
                            value={values.status}
                            onChange={(event) =>
                                update({ status: event.target.value })
                            }
                        >
                            <option value="">Any status</option>
                            <TicketStatusOptions
                                statuses={filterOptions.statuses}
                            />
                        </NativeSelect>
                    </FilterField>

                    <FilterField label="Priority" className="w-32">
                        <NativeSelect
                            value={values.priority}
                            onChange={(event) =>
                                update({ 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="Category" className="w-48">
                        <NativeSelect
                            value={values.category}
                            onChange={(event) =>
                                update({ category: event.target.value })
                            }
                        >
                            <option value="">Any category</option>
                            {filterOptions.categories.map((category) => (
                                <option
                                    key={category.value}
                                    value={category.value}
                                >
                                    {category.label}
                                </option>
                            ))}
                        </NativeSelect>
                    </FilterField>

                    <FilterField label="Installer" className="w-48">
                        <NativeSelect
                            value={values.installer}
                            onChange={(event) =>
                                update({ installer: event.target.value })
                            }
                        >
                            <option value="">Anyone</option>
                            {filterOptions.installers.map((installer) => (
                                <option
                                    key={installer.value}
                                    value={String(installer.value)}
                                >
                                    {installer.label}
                                    {installer.note
                                        ? ` — ${installer.note}`
                                        : ''}
                                </option>
                            ))}
                        </NativeSelect>
                    </FilterField>
                </FilterBar>

                <SegmentedControl
                    value={values.scope}
                    onChange={(scope) => update({ scope })}
                    options={filterOptions.scopes.map((scope) => ({
                        value: scope.value,
                        label: scope.label,
                        count: scopeCounts[scope.value],
                    }))}
                />

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

            {!hasTickets ? (
                <EmptyState
                    icon={LifeBuoy}
                    title={
                        hasAnyTickets
                            ? 'No tickets match these filters'
                            : 'No tickets yet'
                    }
                    description={
                        hasAnyTickets
                            ? 'Try a different status, priority or search term, or widen the scope to every ticket.'
                            : 'Tickets raised by the SMS system land here, matched to the customer, the job and the installer who did it.'
                    }
                    action={
                        hasAnyTickets ? (
                            <Button variant="outline" size="sm" onClick={reset}>
                                <RotateCcw className="size-4" />
                                Clear filters
                            </Button>
                        ) : can.create ? (
                            <Button size="sm" asChild>
                                <Link href={ticketsCreate()}>
                                    <Plus className="size-4" />
                                    Log the first ticket
                                </Link>
                            </Button>
                        ) : undefined
                    }
                />
            ) : (
                <TableCard>
                    <Table>
                        <TableHeader className="[&_th]:text-[11px] [&_th]:font-semibold [&_th]:tracking-wide [&_th]:uppercase">
                            <TableRow>
                                <TableHead>Ticket</TableHead>
                                <TableHead>Customer</TableHead>
                                <TableHead>Job</TableHead>
                                <TableHead>Status</TableHead>
                                <TableHead>Installer</TableHead>
                                <TableHead>Logged</TableHead>
                                <TableHead>Open for</TableHead>
                                <TableHead>Waiting on</TableHead>
                            </TableRow>
                        </TableHeader>
                        <TableBody>
                            {tickets.data.map((ticket) => (
                                <TableRow key={ticket.id} className="group">
                                    <TableCell className="relative">
                                        {ticket.is_overdue ? (
                                            <span
                                                aria-hidden
                                                className="absolute inset-y-1 left-0 w-0.5 rounded-full bg-danger"
                                            />
                                        ) : null}

                                        <div className="flex items-center gap-2">
                                            <StatusDot
                                                tone={ticket.status.color}
                                                pulse={
                                                    ticket.is_overdue &&
                                                    ticket.status.is_open
                                                }
                                            />
                                            <Link
                                                href={ticketShow(ticket.id).url}
                                                className="font-mono text-xs font-medium hover:underline"
                                            >
                                                {ticket.display_number}
                                            </Link>
                                            <span className="text-[11px] text-muted-foreground/60">
                                                {ticket.source.label}
                                            </span>
                                        </div>

                                        <div className="mt-0.5 max-w-[22rem] truncate text-xs text-muted-foreground">
                                            {ticket.issue}
                                        </div>

                                        {/* What kind of work it is, which the
                                            status says nothing about. */}
                                        {ticket.category ? (
                                            <span
                                                className={cn(
                                                    'mt-1 inline-flex items-center rounded-full px-1.5 py-0.5 text-[10px] font-medium',
                                                    toneClassName(
                                                        ticket.category.color,
                                                    ).soft,
                                                )}
                                            >
                                                {ticket.category.label}
                                            </span>
                                        ) : (
                                            <span className="mt-1 inline-block text-[10px] text-muted-foreground/60">
                                                Uncategorised
                                            </span>
                                        )}
                                    </TableCell>

                                    <TableCell>
                                        {ticket.client === null ? (
                                            <span className="text-sm text-warning">
                                                {ticket.contact.name ??
                                                    ticket.contact.phone ??
                                                    'Unknown caller'}
                                            </span>
                                        ) : (
                                            <>
                                                <Link
                                                    href={
                                                        customerShow(
                                                            ticket.client.id,
                                                        ).url
                                                    }
                                                    className="block max-w-[14rem] truncate text-sm hover:underline"
                                                >
                                                    {ticket.client.name}
                                                </Link>
                                                <div className="max-w-[14rem] truncate text-xs text-muted-foreground">
                                                    {ticket.client.phone ??
                                                        ticket.client
                                                            .customer_number}
                                                </div>
                                            </>
                                        )}
                                    </TableCell>

                                    <TableCell>
                                        {ticket.job === null ? (
                                            <span className="text-xs font-medium text-warning">
                                                No job linked
                                            </span>
                                        ) : (
                                            <>
                                                <Link
                                                    href={
                                                        jobShow(ticket.job.id)
                                                            .url
                                                    }
                                                    className="font-mono text-xs font-medium hover:underline"
                                                >
                                                    {ticket.job.job_number}
                                                </Link>
                                                <div className="max-w-[14rem] truncate text-xs text-muted-foreground">
                                                    {ticket.job.title ??
                                                        ticket.job.status_label}
                                                </div>
                                            </>
                                        )}
                                    </TableCell>

                                    <TableCell>
                                        <StatusLabel
                                            tone={ticket.status.color}
                                            quiet={!ticket.status.is_open}
                                        >
                                            {ticket.status.label}
                                        </StatusLabel>
                                        <div className="mt-1.5">
                                            {ticket.priority.value !==
                                            'normal' ? (
                                                <PriorityBadge
                                                    priority={ticket.priority}
                                                />
                                            ) : null}
                                        </div>
                                    </TableCell>

                                    <TableCell className="max-w-[12rem] truncate text-sm">
                                        {ticket.installer === null ? (
                                            <span className="text-muted-foreground">
                                                Unassigned
                                            </span>
                                        ) : (
                                            ticket.installer.name
                                        )}
                                    </TableCell>

                                    <TableCell className="text-xs whitespace-nowrap text-muted-foreground">
                                        {formatDate(ticket.reported_at)}
                                    </TableCell>

                                    <TableCell className="whitespace-nowrap">
                                        <span
                                            className={cn(
                                                'text-sm crm-num',
                                                ticket.is_overdue
                                                    ? 'font-medium text-danger'
                                                    : 'text-muted-foreground',
                                            )}
                                        >
                                            {formatDuration(ticket.days_open)}
                                        </span>
                                        {ticket.is_overdue ? (
                                            <div className="text-[11px] font-medium text-danger">
                                                Overdue
                                            </div>
                                        ) : null}
                                    </TableCell>

                                    <TableCell className="max-w-[12rem] truncate text-xs text-muted-foreground">
                                        {ticket.status.waiting_on}
                                    </TableCell>
                                </TableRow>
                            ))}
                        </TableBody>
                    </Table>

                    <DataPagination page={tickets} noun="tickets" />
                </TableCard>
            )}
        </>
    );
}

TicketsIndex.layout = {
    breadcrumbs: [
        {
            title: 'Tickets',
            href: ticketsIndex(),
        },
    ],
};
