import { Button, Card, Input, Modal, Select, Tooltip } from '@/Components/ui';
import { AdminPageHeader, adminLayout } from '@/Layouts/AdminLayout';
import { cn } from '@/lib/cn';
import { Head, Link, router } from '@inertiajs/react';
import { ChevronDown, ChevronRight } from 'lucide-react';
import { useEffect, useRef, useState, type ReactNode } from 'react';

type Actor = {
    id: number;
    name: string;
    email: string;
};

type LogRow = {
    id: number;
    action: string;
    target_type: string | null;
    target_id: number | null;
    summary: string | null;
    context: Record<string, unknown> | null;
    ip: string | null;
    user_agent: string | null;
    created_at: string | null;
    actor: Actor | null;
};

type Paginated<T> = {
    data: T[];
    current_page: number;
    last_page: number;
    per_page: number;
    total: number;
    links: Array<{ url: string | null; label: string; active: boolean }>;
};

type Filters = {
    action: string;
    target_type: string;
    actor_user_id: number | null;
    target_id: number | null;
    from_date: string;
    to_date: string;
    q: string;
};

type Props = {
    logs: Paginated<LogRow>;
    filters: Filters;
    actions: string[];
    target_types: string[];
};

const RELATIVE_FMT = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

function relativeTime(iso: string | null): string {
    if (!iso) return '—';
    const diffMs = new Date(iso).getTime() - Date.now();
    const absMin = Math.abs(diffMs) / 60_000;
    if (absMin < 1) return 'just now';
    if (absMin < 60)
        return RELATIVE_FMT.format(Math.round(diffMs / 60_000), 'minute');
    if (absMin < 60 * 24)
        return RELATIVE_FMT.format(Math.round(diffMs / 3_600_000), 'hour');
    if (absMin < 60 * 24 * 30)
        return RELATIVE_FMT.format(Math.round(diffMs / 86_400_000), 'day');
    if (absMin < 60 * 24 * 365)
        return RELATIVE_FMT.format(
            Math.round(diffMs / (86_400_000 * 30)),
            'month',
        );
    return RELATIVE_FMT.format(
        Math.round(diffMs / (86_400_000 * 365)),
        'year',
    );
}

function absoluteTime(iso: string | null): string {
    if (!iso) return '';
    try {
        return new Date(iso).toLocaleString();
    } catch {
        return iso;
    }
}

function targetHref(type: string | null, id: number | null): string | null {
    if (!type || id === null || id === undefined) return null;
    switch (type) {
        case 'User':
            return `/admin/users/${id}`;
        case 'Subscription':
            return `/admin/subscriptions/${id}`;
        case 'WebhookEvent':
            return `/admin/webhook-events/${id}`;
        case 'Tenant':
            return `/admin/tenants/${id}`;
        case 'Plan':
            return `/admin/billing`;
        default:
            return null;
    }
}

function truncate(s: string | null, max = 60): string {
    if (!s) return '';
    if (s.length <= max) return s;
    return s.slice(0, max - 1) + '…';
}

function AdminAuditLogIndex({
    logs,
    filters,
    actions,
    target_types,
}: Props) {
    const [form, setForm] = useState<Filters>({
        action: filters.action ?? '',
        target_type: filters.target_type ?? '',
        actor_user_id: filters.actor_user_id ?? null,
        target_id: filters.target_id ?? null,
        from_date: filters.from_date ?? '',
        to_date: filters.to_date ?? '',
        q: filters.q ?? '',
    });

    // Debounced auto-apply matches the rest of admin (Users / Tenants /
    // Subscriptions / Invoices / WebhookEvents). Skip the first effect so
    // the initial render doesn't refetch the page it just rendered.
    const firstRender = useRef(true);
    useEffect(() => {
        if (firstRender.current) {
            firstRender.current = false;
            return;
        }
        const handle = window.setTimeout(() => {
            const sameAction = form.action === (filters.action ?? '');
            const sameTargetType =
                form.target_type === (filters.target_type ?? '');
            const sameActor =
                (form.actor_user_id ?? null) === (filters.actor_user_id ?? null);
            const sameTargetId =
                (form.target_id ?? null) === (filters.target_id ?? null);
            const sameFrom = form.from_date === (filters.from_date ?? '');
            const sameTo = form.to_date === (filters.to_date ?? '');
            const sameQ = form.q === (filters.q ?? '');
            if (
                sameAction &&
                sameTargetType &&
                sameActor &&
                sameTargetId &&
                sameFrom &&
                sameTo &&
                sameQ
            ) {
                return;
            }

            const payload: Record<string, string | number> = {};
            if (form.action) payload.action = form.action;
            if (form.target_type) payload.target_type = form.target_type;
            if (form.actor_user_id !== null) {
                payload.actor_user_id = form.actor_user_id;
            }
            if (form.target_id !== null) payload.target_id = form.target_id;
            if (form.from_date) payload.from_date = form.from_date;
            if (form.to_date) payload.to_date = form.to_date;
            if (form.q) payload.q = form.q;
            router.get('/admin/audit-log', payload, {
                preserveScroll: true,
                preserveState: true,
                replace: true,
            });
        }, 220);
        return () => window.clearTimeout(handle);
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [
        form.action,
        form.target_type,
        form.actor_user_id,
        form.target_id,
        form.from_date,
        form.to_date,
        form.q,
    ]);

    const reset = () => {
        setForm({
            action: '',
            target_type: '',
            actor_user_id: null,
            target_id: null,
            from_date: '',
            to_date: '',
            q: '',
        });
    };

    const filtersDirty =
        form.action ||
        form.target_type ||
        form.actor_user_id !== null ||
        form.target_id !== null ||
        form.from_date ||
        form.to_date ||
        form.q;

    return (
        <>
            <Head title="Admin · Audit log" />
            <AdminPageHeader title="Audit log" description="Append-only record of admin-initiated actions." />
            <div
                    className="mb-3 flex items-center justify-between text-[11px] text-muted-foreground"
                    data-testid="admin-audit-summary"
                >
                    <span>
                        {logs.total === 0
                            ? 'No audit entries match these filters.'
                            : `Showing ${logs.data.length} of ${logs.total} ${logs.total === 1 ? 'entry' : 'entries'}`}
                    </span>
                    {filtersDirty && (
                        <button
                            type="button"
                            onClick={reset}
                            data-testid="admin-audit-reset-inline"
                            className="text-[11px] font-medium text-muted-foreground hover:text-foreground"
                        >
                            Reset
                        </button>
                    )}
                </div>

                <form
                    onSubmit={(e) => e.preventDefault()}
                    className="mb-4 grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-4"
                    data-testid="admin-audit-filters"
                >
                    <FilterField label="Action">
                        <Select
                            value={form.action}
                            onChange={(e) =>
                                setForm((p) => ({ ...p, action: e.target.value }))
                            }
                            data-testid="admin-audit-filter-action"
                        >
                            <option value="">Any</option>
                            {actions.map((a) => (
                                <option key={a} value={a}>
                                    {a}
                                </option>
                            ))}
                        </Select>
                    </FilterField>

                    <FilterField label="Target type">
                        <Select
                            value={form.target_type}
                            onChange={(e) =>
                                setForm((p) => ({
                                    ...p,
                                    target_type: e.target.value,
                                }))
                            }
                            data-testid="admin-audit-filter-target-type"
                        >
                            <option value="">Any</option>
                            {target_types.map((t) => (
                                <option key={t} value={t}>
                                    {t}
                                </option>
                            ))}
                        </Select>
                    </FilterField>

                    <FilterField label="Actor user id">
                        <Input
                            type="number"
                            min={1}
                            value={form.actor_user_id ?? ''}
                            onChange={(e) =>
                                setForm((p) => ({
                                    ...p,
                                    actor_user_id:
                                        e.target.value === ''
                                            ? null
                                            : Number(e.target.value),
                                }))
                            }
                            data-testid="admin-audit-filter-actor"
                        />
                    </FilterField>

                    <FilterField label="Target id">
                        <Input
                            type="number"
                            min={1}
                            value={form.target_id ?? ''}
                            onChange={(e) =>
                                setForm((p) => ({
                                    ...p,
                                    target_id:
                                        e.target.value === ''
                                            ? null
                                            : Number(e.target.value),
                                }))
                            }
                            data-testid="admin-audit-filter-target-id"
                        />
                    </FilterField>

                    <FilterField label="From">
                        <Input
                            type="date"
                            value={form.from_date}
                            onChange={(e) =>
                                setForm((p) => ({
                                    ...p,
                                    from_date: e.target.value,
                                }))
                            }
                            data-testid="admin-audit-filter-from"
                        />
                    </FilterField>

                    <FilterField label="To">
                        <Input
                            type="date"
                            value={form.to_date}
                            onChange={(e) =>
                                setForm((p) => ({
                                    ...p,
                                    to_date: e.target.value,
                                }))
                            }
                            data-testid="admin-audit-filter-to"
                        />
                    </FilterField>

                    <FilterField label="Summary contains">
                        <Input
                            type="text"
                            value={form.q}
                            onChange={(e) =>
                                setForm((p) => ({ ...p, q: e.target.value }))
                            }
                            placeholder="e.g. canceled"
                            data-testid="admin-audit-filter-q"
                        />
                    </FilterField>

                </form>

                <Card padding="none" className="overflow-hidden">
                    <div className="overflow-x-auto">
                        <table className="stagger-rows w-full text-sm">
                            <thead className="border-b border-border bg-muted/30">
                                <tr className="text-left text-[11px] font-medium text-muted-foreground">
                                    <th className="px-4 py-2.5">When</th>
                                    <th className="px-4 py-2.5">Actor</th>
                                    <th className="px-4 py-2.5">Action</th>
                                    <th className="px-4 py-2.5">Target</th>
                                    <th className="px-4 py-2.5">Summary</th>
                                    <th className="px-4 py-2.5">IP</th>
                                    <th className="px-4 py-2.5">User agent</th>
                                    <th className="px-4 py-2.5"></th>
                                </tr>
                            </thead>
                            <tbody>
                                {logs.data.length === 0 ? (
                                    <tr>
                                        <td
                                            colSpan={8}
                                            className="px-4 py-12 text-center text-sm text-muted-foreground"
                                            data-testid="admin-audit-empty"
                                        >
                                            No audit entries match these filters.
                                        </td>
                                    </tr>
                                ) : (
                                    logs.data.map((log) => (
                                        <LogTableRow key={log.id} log={log} />
                                    ))
                                )}
                            </tbody>
                        </table>
                    </div>
                </Card>

            {logs.last_page > 1 && <Pagination paginator={logs} />}
        </>
    );
}

AdminAuditLogIndex.layout = adminLayout;

export default AdminAuditLogIndex;

function FilterField({
    label,
    children,
}: {
    label: string;
    children: ReactNode;
}) {
    return (
        <div>
            <span className="mb-1 block text-[11px] font-medium text-muted-foreground">
                {label}
            </span>
            {children}
        </div>
    );
}

function LogTableRow({ log }: { log: LogRow }) {
    const [expanded, setExpanded] = useState(false);
    const [revertOpen, setRevertOpen] = useState(false);
    const [reverting, setReverting] = useState(false);
    const targetUrl = targetHref(log.target_type, log.target_id);
    const hasContext = log.context && Object.keys(log.context).length > 0;
    const canRevert = log.action === 'theme.applied';

    const onRevert = () => {
        setReverting(true);
        router.post(
            `/admin/audit-log/${log.id}/revert-theme`,
            {},
            {
                preserveScroll: true,
                onFinish: () => {
                    setReverting(false);
                    setRevertOpen(false);
                },
            },
        );
    };
    return (
        <>
            <tr
                className="border-b border-border/60 last:border-0"
                data-testid={`admin-audit-row-${log.id}`}
            >
                <td className="px-4 py-3 align-top text-[12px] text-muted-foreground">
                    <Tooltip label={absoluteTime(log.created_at)}>
                        <span>{relativeTime(log.created_at)}</span>
                    </Tooltip>
                </td>
                <td className="px-4 py-3 align-top">
                    {log.actor ? (
                        <Link
                            href={`/admin/users/${log.actor.id}`}
                            className="block hover:text-accent"
                        >
                            <span className="block font-medium text-foreground">
                                {log.actor.name}
                            </span>
                            <span className="block font-mono text-[11px] text-muted-foreground">
                                {log.actor.email}
                            </span>
                        </Link>
                    ) : (
                        <span className="text-[12px] text-muted-foreground">
                            system
                        </span>
                    )}
                </td>
                <td className="px-4 py-3 align-top">
                    <span className="inline-flex rounded-full border border-border bg-muted px-2 py-0.5 font-mono text-[11px] text-foreground/80">
                        {log.action}
                    </span>
                </td>
                <td className="px-4 py-3 align-top text-[12px]">
                    {log.target_type ? (
                        <span className="text-foreground/80">
                            {log.target_type}
                            {log.target_id !== null && (
                                <>
                                    {' · '}
                                    {targetUrl ? (
                                        <Link
                                            href={targetUrl}
                                            className="font-mono text-foreground hover:text-accent"
                                        >
                                            #{log.target_id}
                                        </Link>
                                    ) : (
                                        <span className="font-mono text-muted-foreground">
                                            #{log.target_id}
                                        </span>
                                    )}
                                </>
                            )}
                        </span>
                    ) : (
                        <span className="text-muted-foreground">—</span>
                    )}
                </td>
                <td className="px-4 py-3 align-top text-[12px] text-foreground/90">
                    <div className="flex items-start gap-1.5">
                        {hasContext && (
                            <button
                                type="button"
                                onClick={() => setExpanded((v) => !v)}
                                className={cn(
                                    'mt-0.5 inline-flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground',
                                )}
                                aria-label={
                                    expanded ? 'Collapse context' : 'Expand context'
                                }
                                data-testid={`admin-audit-toggle-${log.id}`}
                            >
                                {expanded ? (
                                    <ChevronDown
                                        className="h-3.5 w-3.5"
                                        strokeWidth={2}
                                    />
                                ) : (
                                    <ChevronRight
                                        className="h-3.5 w-3.5"
                                        strokeWidth={2}
                                    />
                                )}
                            </button>
                        )}
                        <span className="min-w-0">
                            {log.summary ?? (
                                <span className="text-muted-foreground">—</span>
                            )}
                        </span>
                    </div>
                </td>
                <td className="px-4 py-3 align-top font-mono text-[11px] text-muted-foreground">
                    {log.ip ?? '—'}
                </td>
                <td className="px-4 py-3 align-top text-[11px] text-muted-foreground">
                    {log.user_agent ? (
                        <Tooltip label={log.user_agent}>
                            <span className="cursor-help font-mono">
                                {truncate(log.user_agent, 60)}
                            </span>
                        </Tooltip>
                    ) : (
                        '—'
                    )}
                </td>
                <td className="px-4 py-3 align-top text-right">
                    {canRevert && (
                        <button
                            type="button"
                            onClick={() => setRevertOpen(true)}
                            disabled={reverting}
                            data-testid={`admin-audit-revert-${log.id}`}
                            className="inline-flex h-7 items-center rounded-md border border-border bg-card px-2 text-[11px] font-medium text-foreground/80 transition-colors hover:bg-muted hover:text-foreground disabled:opacity-50"
                        >
                            Revert
                        </button>
                    )}
                </td>
            </tr>
            {revertOpen && (
                <tr>
                    <td colSpan={8}>
                        <RevertConfirmModal
                            onCancel={() => setRevertOpen(false)}
                            onConfirm={onRevert}
                            submitting={reverting}
                            logId={log.id}
                        />
                    </td>
                </tr>
            )}
            {expanded && hasContext && (
                <tr
                    className="border-b border-border/60 bg-muted/30"
                    data-testid={`admin-audit-context-${log.id}`}
                >
                    <td colSpan={8} className="px-4 py-3">
                        <pre className="overflow-x-auto whitespace-pre-wrap break-words rounded-md border border-border bg-card p-3 font-mono text-[11px] text-foreground/85">
                            {JSON.stringify(log.context, null, 2)}
                        </pre>
                    </td>
                </tr>
            )}
        </>
    );
}

function RevertConfirmModal({
    onCancel,
    onConfirm,
    submitting,
    logId,
}: {
    onCancel: () => void;
    onConfirm: () => void;
    submitting: boolean;
    logId: number;
}) {
    return (
        <Modal
            open
            onClose={onCancel}
            size="md"
            closeOnBackdrop={false}
            closeOnEsc={!submitting}
            data-testid={`admin-audit-revert-modal-${logId}`}
        >
            <Modal.Header title="Revert active theme" />
            <Modal.Body fade={false}>
                <p className="text-sm text-muted-foreground">
                    Re-activate the theme that was active before this point?
                    The current theme stays in the version list — you can
                    re-apply it from the appearance editor.
                </p>
            </Modal.Body>
            <Modal.Footer>
                <Button
                    type="button"
                    variant="ghost"
                    onClick={onCancel}
                    disabled={submitting}
                    data-testid={`admin-audit-revert-cancel-${logId}`}
                >
                    Cancel
                </Button>
                <Button
                    type="button"
                    variant="primary"
                    onClick={onConfirm}
                    disabled={submitting}
                    data-testid={`admin-audit-revert-confirm-${logId}`}
                >
                    {submitting ? 'Reverting…' : 'Revert'}
                </Button>
            </Modal.Footer>
        </Modal>
    );
}

function Pagination<T>({ paginator }: { paginator: Paginated<T> }) {
    return (
        <nav
            className="mt-4 flex items-center justify-between"
            data-testid="admin-audit-pagination"
        >
            <span className="text-[11px] text-muted-foreground">
                Page {paginator.current_page} of {paginator.last_page} ·{' '}
                {paginator.total} total
            </span>
            <div className="flex flex-wrap gap-1">
                {paginator.links.map((link, i) => (
                    <button
                        key={`${link.label}-${i}`}
                        type="button"
                        disabled={!link.url}
                        onClick={() => link.url && router.visit(link.url)}
                        className={cn(
                            'rounded-md border border-border px-2.5 py-1 text-[11px] font-medium transition-colors disabled:opacity-40',
                            link.active
                                ? 'border-accent/40 bg-accent/5 text-accent'
                                : 'text-muted-foreground hover:bg-muted hover:text-foreground',
                        )}
                        // The Laravel paginator embeds HTML arrows in labels;
                        // we render them as text — safe because the labels
                        // are server-controlled, not user-supplied.
                        dangerouslySetInnerHTML={{ __html: link.label }}
                    />
                ))}
            </div>
        </nav>
    );
}
