import { Head, Link, router } from "@inertiajs/react";
import {
    ArchiveRestore,
    CalendarDays,
    ChevronDown,
    History,
    LogIn,
    ShieldCheck,
    Users,
} from "lucide-react";
import { useMemo, useState, type FormEvent } from "react";
import {
    EmptyState,
    PageHeader,
} from "@/components/crm/page-header";
import { StatStrip } from "@/components/crm/kpi-tile";
import { NativeSelect } from "@/components/crm/native-select";
import { StatusPill } from "@/components/crm/status-badge";
import {
    DataPagination,
    FilterBar,
    FilterField,
    SearchInput,
    TableCard,
} from "@/components/crm/toolbar";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { formatDate, formatLongDate, initials } from "@/lib/format";
import { cn } from "@/lib/utils";
import type {
    AuditEntry,
    AuditModule,
    AuditStats,
    Option,
    Paginated,
} from "@/types";

type Props = {
    events: Paginated<AuditEntry>;
    filters: {
        search: string | null;
        event: string | null;
        module: string | null;
        actor: string | null;
        from: string | null;
        to: string | null;
    };
    modules: AuditModule[];
    eventTypes: Array<Option & { tone: string }>;
    actors: string[];
    stats: AuditStats;
};

const timeFormatter = new Intl.DateTimeFormat("en-AU", {
    hour: "numeric",
    minute: "2-digit",
});

function timeOf(value: string | null): string {
    if (!value) {
        return "—";
    }

    const date = new Date(value);

    return Number.isNaN(date.getTime()) ? "—" : timeFormatter.format(date);
}

/**
 * The activity log: every change to a record the business cares about.
 *
 * Read top to bottom as a story of the company's data — newest first, grouped
 * by the day it happened. Each line says who did what to which record; opening
 * it shows the fields that moved, from what to what, which is the question
 * anybody actually asks when they come here ("who changed this job's status?").
 */
export default function AuditLog({
    events,
    filters,
    modules,
    eventTypes,
    actors,
    stats,
}: Props) {
    const [search, setSearch] = useState(filters.search ?? "");
    const [event, setEvent] = useState(filters.event ?? "");
    const [module, setModule] = useState(filters.module ?? "");
    const [actor, setActor] = useState(filters.actor ?? "");
    const [from, setFrom] = useState(filters.from ?? "");
    const [to, setTo] = useState(filters.to ?? "");
    const [expanded, setExpanded] = useState<number | null>(null);

    const apply = (next?: {
        search?: string;
        event?: string;
        module?: string;
        actor?: string;
        from?: string;
        to?: string;
    }): void => {
        const params: Record<string, string> = {};

        const values = {
            search: next?.search ?? search,
            event: next?.event ?? event,
            module: next?.module ?? module,
            actor: next?.actor ?? actor,
            from: next?.from ?? from,
            to: next?.to ?? to,
        };

        for (const [key, value] of Object.entries(values)) {
            if (value.trim()) {
                params[key] = value.trim();
            }
        }

        router.get("/settings/audit", params, {
            preserveState: true,
            preserveScroll: true,
            replace: true,
        });
    };

    const submit = (event: FormEvent): void => {
        event.preventDefault();
        apply();
    };

    const reset = (): void => {
        setSearch("");
        setEvent("");
        setModule("");
        setActor("");
        setFrom("");
        setTo("");
        router.get("/settings/audit", {}, { preserveScroll: true, replace: true });
    };

    /**
     * One heading per day, in the order the events arrived.
     */
    const days = useMemo(() => {
        const grouped = new Map<string, AuditEntry[]>();

        for (const entry of events.data) {
            const key = entry.at ? entry.at.slice(0, 10) : "unknown";
            const bucket = grouped.get(key);

            if (bucket) {
                bucket.push(entry);
            } else {
                grouped.set(key, [entry]);
            }
        }

        return [...grouped.entries()];
    }, [events.data]);

    const filtered =
        Boolean(search || event || module || actor || from || to);

    return (
        <>
            <Head title="Activity log" />

            <PageHeader
                eyebrow={
                    <>
                        <ShieldCheck className="size-3.5" />
                        <span>Owner only</span>
                        <span aria-hidden className="text-muted-foreground/50">
                            ·
                        </span>
                        <span>Nothing here can be edited or removed</span>
                    </>
                }
                title="Activity log"
                description="Every record added, edited, hidden or restored across the CRM — written by the records themselves, so nothing slips through. Open a line to see exactly which fields moved."
                actions={
                    <>
                        <Button variant="outline" size="sm" asChild>
                            <Link href="/settings/audit/sign-ins">
                                <LogIn className="size-4" />
                                Sign-in history
                            </Link>
                        </Button>
                        <Button variant="outline" size="sm" asChild>
                            <Link href="/settings/audit/deleted">
                                <ArchiveRestore className="size-4" />
                                Recycle bin
                                {stats.in_bin > 0 ? (
                                    <span className="crm-num bg-danger-soft text-danger rounded px-1.5 py-0.5 text-[10px] font-semibold">
                                        {stats.in_bin}
                                    </span>
                                ) : null}
                            </Link>
                        </Button>
                    </>
                }
            />

            <StatStrip
                items={[
                    {
                        label: "Changes today",
                        value: stats.today,
                        tone: "info",
                        icon: History,
                    },
                    {
                        label: "Last 7 days",
                        value: stats.week,
                        tone: "blue",
                        icon: CalendarDays,
                    },
                    {
                        label: "Hidden this week",
                        value: stats.hidden_this_week,
                        tone: "danger",
                        icon: ArchiveRestore,
                    },
                    {
                        label: "People involved",
                        value: stats.people_this_week,
                        tone: "violet",
                        icon: Users,
                    },
                ]}
            />

            <form onSubmit={submit}>
                <FilterBar
                    actions={
                        <>
                            <Button type="submit" size="sm">
                                Apply
                            </Button>
                            <Button
                                type="button"
                                size="sm"
                                variant="ghost"
                                onClick={reset}
                            >
                                Reset
                            </Button>
                        </>
                    }
                >
                    <FilterField label="Search" className="min-w-[14rem] flex-1">
                        <SearchInput
                            value={search}
                            onChange={setSearch}
                            placeholder="Record, person, email or id"
                        />
                    </FilterField>

                    <FilterField label="Change" className="w-32">
                        <NativeSelect
                            value={event}
                            onChange={(input) => setEvent(input.target.value)}
                        >
                            <option value="">Any</option>
                            {eventTypes.map((type) => (
                                <option key={type.value} value={type.value}>
                                    {type.label}
                                </option>
                            ))}
                        </NativeSelect>
                    </FilterField>

                    <FilterField label="Module" className="w-40">
                        <NativeSelect
                            value={module}
                            onChange={(input) => setModule(input.target.value)}
                        >
                            <option value="">Every module</option>
                            {modules.map((item) => (
                                <option key={item.value} value={item.value}>
                                    {item.label}
                                </option>
                            ))}
                        </NativeSelect>
                    </FilterField>

                    <FilterField label="Person" className="w-44">
                        <NativeSelect
                            value={actor}
                            onChange={(input) => setActor(input.target.value)}
                        >
                            <option value="">Anyone</option>
                            {actors.map((name) => (
                                <option key={name} value={name}>
                                    {name}
                                </option>
                            ))}
                        </NativeSelect>
                    </FilterField>

                    <FilterField label="From" className="w-36">
                        <Input
                            type="date"
                            value={from}
                            onChange={(input) => setFrom(input.target.value)}
                            className="h-9"
                        />
                    </FilterField>

                    <FilterField label="To" className="w-36">
                        <Input
                            type="date"
                            value={to}
                            onChange={(input) => setTo(input.target.value)}
                            className="h-9"
                        />
                    </FilterField>
                </FilterBar>
            </form>

            {events.data.length === 0 ? (
                <TableCard>
                    <EmptyState
                        icon={History}
                        title={
                            filtered
                                ? "No change matches those filters"
                                : "Nothing has been changed yet"
                        }
                        description={
                            filtered
                                ? "Try a different person, module or date range — or reset and browse the whole history."
                                : "The first time somebody adds or edits a client, a job, a ticket, an account or a document, it will appear here."
                        }
                    />
                </TableCard>
            ) : (
                <div className="flex flex-col gap-4">
                    {days.map(([day, entries]) => (
                        <section key={day} className="flex flex-col gap-1.5">
                            <div className="flex items-baseline justify-between gap-3 px-1">
                                <h2 className="text-xs font-semibold tracking-wide uppercase">
                                    {day === "unknown"
                                        ? "Undated"
                                        : formatLongDate(`${day}T00:00:00`)}
                                </h2>
                                <span className="text-muted-foreground text-[11px]">
                                    {entries.length}{" "}
                                    {entries.length === 1 ? "change" : "changes"}
                                </span>
                            </div>

                            <TableCard>
                                <ul className="divide-hairline divide-y">
                                    {entries.map((entry) => (
                                        <AuditRow
                                            key={entry.id}
                                            entry={entry}
                                            open={expanded === entry.id}
                                            onToggle={() =>
                                                setExpanded(
                                                    expanded === entry.id
                                                        ? null
                                                        : entry.id,
                                                )
                                            }
                                        />
                                    ))}
                                </ul>
                            </TableCard>
                        </section>
                    ))}
                </div>
            )}

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

function AuditRow({
    entry,
    open,
    onToggle,
}: {
    entry: AuditEntry;
    open: boolean;
    onToggle: () => void;
}) {
    const canOpen = entry.changes.length > 0;

    return (
        <li className={cn("px-4 py-2.5", open && "bg-accent/30")}>
            <div className="flex items-start gap-3">
                <span
                    aria-hidden
                    className="mt-2 w-12 shrink-0 text-right text-[11px] tabular-nums text-muted-foreground"
                >
                    {timeOf(entry.at)}
                </span>

                <span
                    aria-hidden
                    className={cn(
                        "mt-2 flex size-6 shrink-0 items-center justify-center rounded-full text-[10px] font-semibold",
                        entry.actor.kind === "system"
                            ? "bg-muted text-muted-foreground"
                            : "bg-solar-soft text-solar-ink",
                    )}
                >
                    {entry.actor.kind === "system"
                        ? "SY"
                        : initials(entry.actor.name)}
                </span>

                <div className="min-w-0 flex-1">
                    <div className="flex flex-wrap items-center gap-x-2 gap-y-1">
                        <span className="text-sm">
                            <span className="font-medium">
                                {entry.actor.name}
                            </span>{" "}
                            <span className="text-muted-foreground">
                                {entry.event.verb}
                            </span>{" "}
                            <span className="font-medium">
                                {entry.record.title}
                            </span>
                        </span>

                        <StatusPill tone={entry.event.tone}>
                            {entry.event.label}
                        </StatusPill>

                        <StatusPill tone={entry.tone}>
                            {entry.module}
                        </StatusPill>

                        {entry.record.hidden ? (
                            <span className="text-danger text-[11px] font-medium">
                                hidden now
                            </span>
                        ) : null}
                    </div>

                    <p className="mt-0.5 text-[11px] text-muted-foreground">
                        {entry.record.kind} · {entry.actor.kind_label}
                        {entry.actor.email ? ` · ${entry.actor.email}` : ""}
                        {entry.fields.length > 0
                            ? ` · ${entry.fields.slice(0, 4).join(", ")}${
                                  entry.fields.length > 4
                                      ? ` +${entry.fields.length - 4} more`
                                      : ""
                              }`
                            : ""}
                    </p>
                </div>

                <div className="flex shrink-0 items-center gap-1">
                    {entry.record.url ? (
                        <Button variant="ghost" size="sm" asChild>
                            <a href={entry.record.url}>Open</a>
                        </Button>
                    ) : null}

                    {canOpen ? (
                        <Button
                            type="button"
                            variant="ghost"
                            size="icon"
                            aria-expanded={open}
                            aria-label={open ? "Hide the details" : "Show what changed"}
                            onClick={onToggle}
                            className="size-7"
                        >
                            <ChevronDown
                                className={cn(
                                    "size-4 transition-transform",
                                    open && "rotate-180",
                                )}
                            />
                        </Button>
                    ) : null}
                </div>
            </div>

            {open && canOpen ? (
                <div className="mt-2.5 ml-[4.5rem] grid gap-2">
                    <div className="ring-hairline overflow-hidden rounded-lg ring-1">
                        <table className="w-full text-xs">
                            <thead className="bg-muted/60">
                                <tr>
                                    <th className="w-40 px-3 py-1.5 text-left font-semibold">
                                        Field
                                    </th>
                                    <th className="px-3 py-1.5 text-left font-semibold">
                                        Was
                                    </th>
                                    <th className="px-3 py-1.5 text-left font-semibold">
                                        Now
                                    </th>
                                </tr>
                            </thead>
                            <tbody className="divide-hairline divide-y">
                                {entry.changes.map((change) => (
                                    <tr key={change.field}>
                                        <td className="px-3 py-1.5 font-medium">
                                            {change.label}
                                        </td>
                                        <td className="text-muted-foreground px-3 py-1.5">
                                            {change.old ?? "—"}
                                        </td>
                                        <td className="px-3 py-1.5">
                                            {change.new ?? "—"}
                                        </td>
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    </div>

                    <p className="text-[11px] text-muted-foreground">
                        {entry.at ? formatDate(entry.at) : "—"}
                        {entry.ip ? ` · ${entry.ip}` : ""} · {entry.device} ·
                        Record #{entry.record.id}
                    </p>
                </div>
            ) : null}
        </li>
    );
}
