import AppNav from '@/Components/AppNav';
import { Card, Select } from '@/Components/ui';
import { cn } from '@/lib/cn';
import { Head, router } from '@inertiajs/react';
import {
    Activity as ActivityIcon,
    FilePlus2,
    FolderMinus,
    FolderPlus,
    Mail,
    Pencil,
    ShieldCheck,
    Trash2,
    UserMinus,
    type LucideIcon,
} from 'lucide-react';

/**
 * Per-workspace activity log (Team Workspaces) — the tenant-facing "who did
 * what" trail for owners/admins. Reads the same `audit_logs` rows as the
 * operator's admin log, scoped to this workspace server-side. Newest-first,
 * paginated. Summaries are pre-rendered server-side (human-readable).
 */
type Actor = {
    name: string | null;
    email: string | null;
    role: string | null;
};

type Event = {
    id: number;
    action: string;
    summary: string | null;
    actor: Actor | null;
    created_at: string | null;
};

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

type Props = {
    workspace: { id: number; name: string };
    events: Paginated<Event>;
    actors: Array<{ id: number; name: string; email: string }>;
    filters: { type: string; actor: number | null };
};

const TYPE_TABS: Array<{ key: string; label: string }> = [
    { key: 'all', label: 'All' },
    { key: 'members', label: 'Members' },
    { key: 'projects', label: 'Projects' },
    { key: 'invites', label: 'Invites' },
    { key: 'settings', label: 'Settings' },
];

function roleLabel(role: string): string {
    return role.charAt(0).toUpperCase() + role.slice(1);
}

/** Owner/Admin = accent (privileged); Editor/Viewer = neutral. */
function roleBadgeClasses(role: string): string {
    return role === 'owner' || role === 'admin'
        ? 'border-accent/30 bg-accent/10 text-accent'
        : 'border-border bg-muted text-muted-foreground';
}

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

function relativeTime(iso: string | null): string {
    if (!iso) return '';
    const ms = new Date(iso).getTime();
    if (Number.isNaN(ms)) return '';
    const diffMs = ms - 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');
    return RELATIVE_FMT.format(Math.round(diffMs / (86_400_000 * 30)), 'month');
}

// Map each audit action to an icon + tone. Unknown actions fall through to a
// neutral activity glyph.
function iconFor(action: string): { Icon: LucideIcon; tone: string } {
    if (action.startsWith('workspace.invite'))
        return { Icon: Mail, tone: 'text-accent' };
    if (action === 'workspace.member.removed' || action === 'workspace.member.left')
        return { Icon: UserMinus, tone: 'text-destructive' };
    if (action === 'workspace.role.changed')
        return { Icon: ShieldCheck, tone: 'text-accent' };
    if (action === 'workspace.project.created')
        return { Icon: FilePlus2, tone: 'text-success' };
    if (action === 'workspace.project.deleted')
        return { Icon: Trash2, tone: 'text-destructive' };
    if (action === 'workspace.project.shared')
        return { Icon: FolderPlus, tone: 'text-success' };
    if (action === 'workspace.project.unshared')
        return { Icon: FolderMinus, tone: 'text-destructive' };
    if (action === 'workspace.renamed')
        return { Icon: Pencil, tone: 'text-muted-foreground' };
    return { Icon: ActivityIcon, tone: 'text-muted-foreground' };
}

export default function WorkspaceActivity({
    workspace,
    events,
    actors,
    filters,
}: Props) {
    // Names that appear more than once among members — only THESE get an
    // `(email)` suffix, so unique names stay clean.
    const dupNames = new Set(
        Object.entries(
            actors.reduce<Record<string, number>>((acc, a) => {
                acc[a.name] = (acc[a.name] ?? 0) + 1;
                return acc;
            }, {}),
        )
            .filter(([, n]) => n > 1)
            .map(([name]) => name),
    );

    // Actor display: name, suffixed with the email only when the name collides
    // with another member's. Falls back to email, then "Removed member".
    const actorName = (actor: Actor | null): string => {
        if (!actor) return 'Removed member';
        const name = actor.name ?? actor.email ?? 'Unknown';
        if (actor.name && actor.email && dupNames.has(actor.name)) {
            return `${name} (${actor.email})`;
        }
        return name;
    };

    const optionLabel = (a: { name: string; email: string }): string =>
        dupNames.has(a.name) ? `${a.name} (${a.email})` : a.name;

    // Navigate with the merged filter set; reset to page 1 on any change.
    const applyFilter = (next: { type?: string; actor?: number | null }) => {
        const type = next.type ?? filters.type;
        const actor =
            next.actor === undefined ? filters.actor : next.actor;
        router.get(
            '/workspace/activity',
            {
                ...(type && type !== 'all' ? { type } : {}),
                ...(actor != null ? { actor } : {}),
            },
            { preserveScroll: true, preserveState: true },
        );
    };

    return (
        <>
            <Head title="Workspace activity" />
            <div className="flex min-h-screen flex-col bg-background text-foreground">
                <AppNav />
                <main className="mx-auto w-full max-w-2xl flex-1 px-6 py-8">
                    <div>
                        <h1 className="text-xl font-semibold tracking-tight">
                            Activity
                        </h1>
                        <p className="mt-1 text-[12px] text-muted-foreground">
                            Recent changes in {workspace.name}
                        </p>
                    </div>

                    {/* Filters — type tabs + actor select. */}
                    <div className="mt-5 flex flex-wrap items-center justify-between gap-3">
                        <div
                            className="flex flex-wrap gap-1"
                            data-testid="activity-type-tabs"
                        >
                            {TYPE_TABS.map((tab) => {
                                const active = filters.type === tab.key;
                                return (
                                    <button
                                        key={tab.key}
                                        type="button"
                                        onClick={() =>
                                            applyFilter({ type: tab.key })
                                        }
                                        data-testid={`activity-type-${tab.key}`}
                                        className={cn(
                                            'rounded-md border px-2.5 py-1 text-[12px] font-medium transition-colors',
                                            active
                                                ? 'border-accent/40 bg-accent/10 text-accent'
                                                : 'border-border text-muted-foreground hover:bg-muted hover:text-foreground',
                                        )}
                                    >
                                        {tab.label}
                                    </button>
                                );
                            })}
                        </div>
                        <Select
                            value={filters.actor ?? ''}
                            onChange={(e) =>
                                applyFilter({
                                    actor: e.target.value
                                        ? Number(e.target.value)
                                        : null,
                                })
                            }
                            data-testid="activity-actor-filter"
                            wrapperClassName="w-28"
                            className="h-8 rounded-md py-1 pl-2.5 pr-7 text-[12px] shadow-none"
                        >
                            <option value="">Everyone</option>
                            {actors.map((a) => (
                                <option key={a.id} value={a.id}>
                                    {optionLabel(a)}
                                </option>
                            ))}
                        </Select>
                    </div>

                    <Card padding="none" className="mt-4 overflow-hidden">
                        {events.data.length === 0 ? (
                            <div
                                className="flex flex-col items-center gap-2 px-6 py-16 text-center"
                                data-testid="activity-empty"
                            >
                                <ActivityIcon
                                    className="h-6 w-6 text-muted-foreground/50"
                                    strokeWidth={1.5}
                                />
                                <p className="text-[12px] text-muted-foreground">
                                    {filters.type !== 'all' || filters.actor != null
                                        ? 'No activity matches these filters.'
                                        : 'No workspace activity yet.'}
                                </p>
                            </div>
                        ) : (
                            <ul className="divide-y divide-border">
                                {events.data.map((ev) => {
                                    const { Icon, tone } = iconFor(ev.action);
                                    return (
                                        <li
                                            key={ev.id}
                                            data-testid={`activity-row-${ev.id}`}
                                            className="flex items-start gap-3 px-4 py-3"
                                        >
                                            <Icon
                                                className={cn(
                                                    'mt-0.5 h-4 w-4 shrink-0',
                                                    tone,
                                                )}
                                                strokeWidth={2}
                                            />
                                            <div className="min-w-0 flex-1">
                                                <p className="text-[13px] text-foreground">
                                                    {ev.summary ?? ev.action}
                                                </p>
                                                <p className="mt-1 flex flex-wrap items-center gap-1.5 text-[11px] text-muted-foreground/70">
                                                    {ev.actor?.role && (
                                                        <span
                                                            className={cn(
                                                                'rounded-sm border px-1 text-[9px] font-medium uppercase tracking-wider',
                                                                roleBadgeClasses(
                                                                    ev.actor.role,
                                                                ),
                                                            )}
                                                        >
                                                            {roleLabel(ev.actor.role)}
                                                        </span>
                                                    )}
                                                    <span>{actorName(ev.actor)}</span>
                                                    <span aria-hidden>·</span>
                                                    <span>
                                                        {relativeTime(ev.created_at)}
                                                    </span>
                                                </p>
                                            </div>
                                        </li>
                                    );
                                })}
                            </ul>
                        )}
                    </Card>

                    {events.last_page > 1 && (
                        <nav className="mt-4 flex items-center justify-between">
                            <span className="text-[11px] text-muted-foreground">
                                Page {events.current_page} of {events.last_page} ·{' '}
                                {events.total} total
                            </span>
                            <div className="flex flex-wrap gap-1">
                                {events.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',
                                        )}
                                        dangerouslySetInnerHTML={{ __html: link.label }}
                                    />
                                ))}
                            </div>
                        </nav>
                    )}
                </main>
            </div>
        </>
    );
}
