import { useCallback, useEffect, useMemo, useState } from 'react';
import {
    CheckCircle,
    ChevronDown,
    ChevronRight,
    RefreshCw,
    ShieldAlert,
} from 'lucide-react';
import { ListPagination } from '../../../components/ListPagination';
import { forensicSeverityBadgeClass } from '../../../utils/forensics';
import { timeAgo } from '../../../utils/timeAgo';
import type { ActiveIncident, IncidentAttackGroup, IncidentFilterId } from '../types/activeIncident';
import {
    GROUPS_PER_PAGE,
    INCIDENTS_PER_PAGE,
    SITES_INITIAL_VISIBLE,
    SITES_LOAD_MORE_STEP,
    buildFilterChips,
    defaultPanelExpanded,
    extractSourceIp,
    filterIncidents,
    groupExpansionDefaults,
    groupIncidents,
    highestSeverity,
    incidentTitle,
    panelAccentClass,
    panelContainerClass,
    siteBucketKey,
} from '../utils/incidentQueue';

interface ActiveIncidentsPanelProps {
    incidents: ActiveIncident[];
    lastUpdated: Date | null;
    isRefreshing: boolean;
    incidentActionId: number | null;
    nowTick: number;
    onRefresh: () => void;
    onOpenQueue: () => void;
    onInvestigate: (incident: ActiveIncident) => void;
    onAcknowledge: (incidentId: number) => Promise<void>;
    onResolve: (incidentId: number) => Promise<void>;
    onBulkAcknowledge: (incidentIds: number[]) => Promise<void>;
    onBulkResolve: (incidentIds: number[]) => Promise<void>;
    onOpenDrawer: (incident: ActiveIncident) => void;
}

function AutoHandledBadge() {
    return (
        <span className="inline-flex rounded-md border border-emerald-500/20 bg-emerald-500/10 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-emerald-300">
            Auto-handled
        </span>
    );
}

function ReviewRequiredBadge() {
    return (
        <span className="inline-flex rounded-md border border-rose-500/20 bg-rose-500/10 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-rose-300">
            Review required
        </span>
    );
}

interface IncidentRowProps {
    incident: ActiveIncident;
    nowTick: number;
    incidentActionId: number | null;
    selected: boolean;
    onToggleSelect: (incidentId: number) => void;
    onInvestigate: (incident: ActiveIncident) => void;
    onAcknowledge: (incidentId: number) => void;
    onResolve: (incidentId: number) => void;
    onOpenDrawer: (incident: ActiveIncident) => void;
}

function IncidentRow({
    incident,
    nowTick,
    incidentActionId,
    selected,
    onToggleSelect,
    onInvestigate,
    onAcknowledge,
    onResolve,
    onOpenDrawer,
}: IncidentRowProps) {
    const ip = extractSourceIp(incident);

    return (
        <div className="flex gap-2 border-t border-slate-800/50 px-3 py-2.5 first:border-t-0">
            <input
                type="checkbox"
                checked={selected}
                onChange={() => onToggleSelect(incident.id)}
                className="mt-1 h-3.5 w-3.5 shrink-0 rounded border-slate-700 bg-slate-900 text-rose-500 focus:ring-rose-500/30"
                aria-label={`Select incident ${incident.id}`}
            />
            <button
                type="button"
                onClick={() => onOpenDrawer(incident)}
                className="min-w-0 flex-1 text-left transition hover:opacity-90"
            >
                <p className="text-xs font-semibold text-slate-100">{incidentTitle(incident)}</p>
                <p className="mt-1 text-[10px] text-slate-400">{incident.agent?.site_name ?? incident.agent_id}</p>
                {ip ? <p className="font-mono text-[10px] text-slate-500">{ip}</p> : null}
                <p className="mt-0.5 text-[10px] text-slate-600">{timeAgo(incident.logged_at, nowTick)}</p>
            </button>
            <div className="flex shrink-0 flex-col gap-1 sm:flex-row sm:items-center">
                <button
                    type="button"
                    onClick={() => onInvestigate(incident)}
                    className="rounded-md border border-slate-700/70 px-2 py-1 text-[9px] font-semibold text-slate-300 transition hover:bg-slate-800"
                >
                    Investigate
                </button>
                <button
                    type="button"
                    disabled={incidentActionId === incident.id}
                    onClick={() => onAcknowledge(incident.id)}
                    className="rounded-md border border-amber-500/25 px-2 py-1 text-[9px] font-semibold text-amber-300 transition hover:bg-amber-500/10 disabled:opacity-50"
                >
                    Acknowledge
                </button>
                <button
                    type="button"
                    disabled={incidentActionId === incident.id}
                    onClick={() => onResolve(incident.id)}
                    className="rounded-md border border-emerald-500/25 px-2 py-1 text-[9px] font-semibold text-emerald-300 transition hover:bg-emerald-500/10 disabled:opacity-50"
                >
                    Resolve
                </button>
            </div>
        </div>
    );
}

interface SiteBucketSectionProps {
    bucket: IncidentAttackGroup['siteBuckets'][number];
    nowTick: number;
    incidentActionId: number | null;
    expanded: boolean;
    selectedIds: Set<number>;
    incidentPage: number;
    onToggleExpanded: () => void;
    onToggleSelect: (incidentId: number) => void;
    onIncidentPageChange: (page: number) => void;
    onInvestigate: (incident: ActiveIncident) => void;
    onAcknowledge: (incidentId: number) => void;
    onResolve: (incidentId: number) => void;
    onOpenDrawer: (incident: ActiveIncident) => void;
}

function SiteBucketSection({
    bucket,
    nowTick,
    incidentActionId,
    expanded,
    selectedIds,
    incidentPage,
    onToggleExpanded,
    onToggleSelect,
    onIncidentPageChange,
    onInvestigate,
    onAcknowledge,
    onResolve,
    onOpenDrawer,
}: SiteBucketSectionProps) {
    const totalPages = Math.max(1, Math.ceil(bucket.incidents.length / INCIDENTS_PER_PAGE));
    const start = (incidentPage - 1) * INCIDENTS_PER_PAGE;
    const visibleIncidents = expanded
        ? bucket.incidents.slice(start, start + INCIDENTS_PER_PAGE)
        : [];

    return (
        <div className="rounded-xl border border-slate-800/70 bg-slate-950/35">
            <button
                type="button"
                aria-expanded={expanded}
                onClick={onToggleExpanded}
                className="flex w-full items-center justify-between gap-3 px-3 py-2.5 text-left transition hover:bg-slate-900/40"
            >
                <span className="min-w-0">
                    <span className="block truncate text-xs font-semibold text-white">{bucket.siteName}</span>
                    <span className="mt-0.5 block text-[10px] text-slate-500">
                        {bucket.incidents.length} event{bucket.incidents.length === 1 ? '' : 's'}
                        {' · '}
                        Last {timeAgo(bucket.lastSeen, nowTick)}
                    </span>
                </span>
                <ChevronDown
                    className={`h-4 w-4 shrink-0 text-slate-500 transition-transform duration-200 ${expanded ? 'rotate-180' : ''}`}
                />
            </button>

            {expanded ? (
                <div className="border-t border-slate-800/60">
                    {visibleIncidents.map((incident) => (
                        <IncidentRow
                            key={incident.id}
                            incident={incident}
                            nowTick={nowTick}
                            incidentActionId={incidentActionId}
                            selected={selectedIds.has(incident.id)}
                            onToggleSelect={onToggleSelect}
                            onInvestigate={onInvestigate}
                            onAcknowledge={onAcknowledge}
                            onResolve={onResolve}
                            onOpenDrawer={onOpenDrawer}
                        />
                    ))}
                    <ListPagination
                        page={incidentPage}
                        totalPages={totalPages}
                        totalItems={bucket.incidents.length}
                        pageSize={INCIDENTS_PER_PAGE}
                        onPageChange={onIncidentPageChange}
                    />
                </div>
            ) : null}
        </div>
    );
}

interface AttackGroupCardProps {
    group: IncidentAttackGroup;
    nowTick: number;
    incidentActionId: number | null;
    expanded: boolean;
    expandedSites: Set<string>;
    siteVisibleCount: number;
    selectedIds: Set<number>;
    siteIncidentPages: Record<string, number>;
    onToggleGroup: () => void;
    onToggleSite: (siteKey: string) => void;
    onShowMoreSites: () => void;
    onToggleSelect: (incidentId: number) => void;
    onSiteIncidentPageChange: (siteKey: string, page: number) => void;
    onInvestigate: (incident: ActiveIncident) => void;
    onAcknowledge: (incidentId: number) => void;
    onResolve: (incidentId: number) => void;
    onOpenDrawer: (incident: ActiveIncident) => void;
}

function AttackGroupCard({
    group,
    nowTick,
    incidentActionId,
    expanded,
    expandedSites,
    siteVisibleCount,
    selectedIds,
    siteIncidentPages,
    onToggleGroup,
    onToggleSite,
    onShowMoreSites,
    onToggleSelect,
    onSiteIncidentPageChange,
    onInvestigate,
    onAcknowledge,
    onResolve,
    onOpenDrawer,
}: AttackGroupCardProps) {
    const visibleBuckets = expanded ? group.siteBuckets.slice(0, siteVisibleCount) : [];
    const calm = group.allAutoHandled && !group.requiresReview;

    return (
        <article
            className={`overflow-hidden rounded-xl border ${
                calm ? 'border-slate-800/80 bg-slate-950/25' : 'border-slate-700/80 bg-slate-950/40'
            }`}
        >
            <button
                type="button"
                aria-expanded={expanded}
                onClick={onToggleGroup}
                className="flex w-full items-start gap-3 px-4 py-3 text-left transition hover:bg-slate-900/30"
            >
                <ChevronRight
                    className={`mt-0.5 h-4 w-4 shrink-0 text-slate-500 transition-transform duration-200 ${expanded ? 'rotate-90' : ''}`}
                />
                <span className="min-w-0 flex-1">
                    <span className="flex flex-wrap items-center gap-2">
                        <span className="text-sm font-bold text-white">{group.attackTypeLabel}</span>
                        <span className={`rounded border px-1.5 py-0.5 text-[9px] font-bold uppercase ${forensicSeverityBadgeClass(group.severityLabel)}`}>
                            {group.severityLabel}
                        </span>
                        {group.allAutoHandled ? <AutoHandledBadge /> : null}
                        {group.requiresReview ? <ReviewRequiredBadge /> : null}
                    </span>
                    <span className="mt-1 flex flex-wrap gap-x-3 gap-y-1 text-[10px] text-slate-500">
                        <span>{group.eventCount} event{group.eventCount === 1 ? '' : 's'}</span>
                        <span>{group.siteCount} website{group.siteCount === 1 ? '' : 's'}</span>
                        <span>Last seen {timeAgo(group.lastSeen, nowTick)}</span>
                    </span>
                </span>
            </button>

            {expanded ? (
                <div className="space-y-2 border-t border-slate-800/60 px-3 py-3">
                    {visibleBuckets.map((bucket) => {
                        const siteKey = siteBucketKey(group.key, bucket.agentId);
                        return (
                            <SiteBucketSection
                                key={siteKey}
                                bucket={bucket}
                                nowTick={nowTick}
                                incidentActionId={incidentActionId}
                                expanded={expandedSites.has(siteKey)}
                                selectedIds={selectedIds}
                                incidentPage={siteIncidentPages[siteKey] ?? 1}
                                onToggleExpanded={() => onToggleSite(siteKey)}
                                onToggleSelect={onToggleSelect}
                                onIncidentPageChange={(page) => onSiteIncidentPageChange(siteKey, page)}
                                onInvestigate={onInvestigate}
                                onAcknowledge={onAcknowledge}
                                onResolve={onResolve}
                                onOpenDrawer={onOpenDrawer}
                            />
                        );
                    })}
                    {group.siteBuckets.length > siteVisibleCount ? (
                        <button
                            type="button"
                            onClick={onShowMoreSites}
                            className="w-full rounded-lg border border-slate-800 px-3 py-2 text-[10px] font-semibold text-slate-400 transition hover:bg-slate-800/40 hover:text-white"
                        >
                            Show more websites ({group.siteBuckets.length - siteVisibleCount} remaining)
                        </button>
                    ) : null}
                </div>
            ) : null}
        </article>
    );
}

export function ActiveIncidentsPanel({
    incidents,
    lastUpdated,
    isRefreshing,
    incidentActionId,
    nowTick,
    onRefresh,
    onOpenQueue,
    onInvestigate,
    onAcknowledge,
    onResolve,
    onBulkAcknowledge,
    onBulkResolve,
    onOpenDrawer,
}: ActiveIncidentsPanelProps) {
    const [panelOpen, setPanelOpen] = useState(false);
    const [panelInitialized, setPanelInitialized] = useState(false);
    const [activeFilter, setActiveFilter] = useState<IncidentFilterId>('all');
    const [expandedGroups, setExpandedGroups] = useState<Set<string>>(new Set());
    const [expandedSites, setExpandedSites] = useState<Set<string>>(new Set());
    const [siteVisibleCounts, setSiteVisibleCounts] = useState<Record<string, number>>({});
    const [siteIncidentPages, setSiteIncidentPages] = useState<Record<string, number>>({});
    const [selectedIds, setSelectedIds] = useState<Set<number>>(new Set());
    const [groupPage, setGroupPage] = useState(1);
    const [bulkProcessing, setBulkProcessing] = useState(false);

    const topSeverity = highestSeverity(incidents);
    const accent = panelAccentClass(topSeverity);
    const filterChips = useMemo(() => buildFilterChips(incidents), [incidents]);
    const filteredIncidents = useMemo(
        () => filterIncidents(incidents, activeFilter),
        [incidents, activeFilter],
    );
    const attackGroups = useMemo(() => groupIncidents(filteredIncidents), [filteredIncidents]);
    const groupTotalPages = Math.max(1, Math.ceil(attackGroups.length / GROUPS_PER_PAGE));
    const paginatedGroups = useMemo(() => {
        const start = (groupPage - 1) * GROUPS_PER_PAGE;
        return attackGroups.slice(start, start + GROUPS_PER_PAGE);
    }, [attackGroups, groupPage]);

    useEffect(() => {
        if (panelInitialized || incidents.length === 0) {
            return;
        }

        setPanelOpen(defaultPanelExpanded(incidents));
        setExpandedGroups(groupExpansionDefaults(groupIncidents(incidents)));
        setPanelInitialized(true);
    }, [incidents, panelInitialized]);

    useEffect(() => {
        if (groupPage > groupTotalPages) {
            setGroupPage(groupTotalPages);
        }
    }, [groupPage, groupTotalPages]);

    useEffect(() => {
        setGroupPage(1);
        setSelectedIds(new Set());
    }, [activeFilter]);

    const toggleGroup = useCallback((groupKey: string) => {
        setExpandedGroups((current) => {
            const next = new Set(current);
            if (next.has(groupKey)) {
                next.delete(groupKey);
            } else {
                next.add(groupKey);
            }
            return next;
        });
    }, []);

    const toggleSite = useCallback((siteKey: string) => {
        setExpandedSites((current) => {
            const next = new Set(current);
            if (next.has(siteKey)) {
                next.delete(siteKey);
            } else {
                next.add(siteKey);
            }
            return next;
        });
    }, []);

    const expandAll = useCallback(() => {
        setExpandedGroups(new Set(attackGroups.map((group) => group.key)));
        const allSites = new Set<string>();
        attackGroups.forEach((group) => {
            group.siteBuckets.forEach((bucket) => {
                allSites.add(siteBucketKey(group.key, bucket.agentId));
            });
            setSiteVisibleCounts((current) => ({
                ...current,
                [group.key]: group.siteBuckets.length,
            }));
        });
        setExpandedSites(allSites);
    }, [attackGroups]);

    const collapseAll = useCallback(() => {
        setExpandedGroups(new Set());
        setExpandedSites(new Set());
    }, []);

    const toggleSelect = useCallback((incidentId: number) => {
        setSelectedIds((current) => {
            const next = new Set(current);
            if (next.has(incidentId)) {
                next.delete(incidentId);
            } else {
                next.add(incidentId);
            }
            return next;
        });
    }, []);

    const runBulk = useCallback(async (ids: number[], action: 'acknowledge' | 'resolve') => {
        if (ids.length === 0) {
            return;
        }

        setBulkProcessing(true);
        try {
            if (action === 'acknowledge') {
                await onBulkAcknowledge(ids);
            } else {
                await onBulkResolve(ids);
            }
            setSelectedIds(new Set());
        } finally {
            setBulkProcessing(false);
        }
    }, [onBulkAcknowledge, onBulkResolve]);

    const acknowledgeAllVisible = useCallback(() => {
        void runBulk(filteredIncidents.map((incident) => incident.id), 'acknowledge');
    }, [filteredIncidents, runBulk]);

    const resolveSelected = useCallback(() => {
        void runBulk([...selectedIds], 'resolve');
    }, [runBulk, selectedIds]);

    return (
        <section
            className={`overflow-hidden rounded-2xl border ${panelContainerClass(topSeverity)}`}
            aria-labelledby="active-incidents-heading"
        >
            <div className="flex items-center justify-between gap-3 px-4 py-3">
                <button
                    type="button"
                    aria-expanded={panelOpen}
                    onClick={() => setPanelOpen((value) => !value)}
                    className="flex min-w-0 flex-1 items-center gap-3 text-left transition hover:opacity-90"
                >
                    <span className={`flex h-8 w-8 shrink-0 items-center justify-center rounded-xl border ${accent.icon}`}>
                        {incidents.length
                            ? <ShieldAlert className="h-4 w-4" />
                            : <CheckCircle className="h-4 w-4" />}
                    </span>
                    <span className="min-w-0 flex-1">
                        <span className="flex items-center gap-2">
                            {incidents.length > 0 && accent.pulse ? (
                                <span className="h-1.5 w-1.5 animate-pulse rounded-full bg-rose-500" />
                            ) : null}
                            <span id="active-incidents-heading" className={`text-xs font-bold uppercase tracking-[0.16em] ${accent.text}`}>
                                {incidents.length
                                    ? `${incidents.length} active incident${incidents.length === 1 ? '' : 's'}`
                                    : 'No active incidents'}
                            </span>
                        </span>
                        {lastUpdated ? (
                            <span className="mt-0.5 block text-[10px] text-slate-500">
                                Updated {lastUpdated.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
                            </span>
                        ) : null}
                    </span>
                    {incidents.length > 0 ? (
                        <ChevronDown
                            className={`h-4 w-4 shrink-0 text-slate-500 transition-transform duration-200 ${panelOpen ? 'rotate-180' : ''}`}
                        />
                    ) : null}
                </button>

                <div className="flex shrink-0 items-center gap-2">
                    <button
                        type="button"
                        onClick={onRefresh}
                        className="rounded-lg border border-slate-700/70 p-2 text-slate-400 transition hover:bg-slate-800 hover:text-white"
                        title="Refresh dashboard"
                    >
                        <RefreshCw className={`h-3.5 w-3.5 ${isRefreshing ? 'animate-spin' : ''}`} />
                    </button>
                    {incidents.length > 0 ? (
                        <button
                            type="button"
                            onClick={onOpenQueue}
                            className="rounded-lg border border-slate-700/80 bg-slate-900/60 px-3 py-1.5 text-xs font-semibold text-slate-200 transition hover:bg-slate-800"
                        >
                            Open queue
                        </button>
                    ) : null}
                </div>
            </div>

            {panelOpen && incidents.length > 0 ? (
                <div className={`border-t ${accent.border}`}>
                    <div className="flex flex-wrap gap-1.5 px-4 py-3">
                        {filterChips.map((chip) => (
                            <button
                                key={chip.id}
                                type="button"
                                onClick={() => setActiveFilter(chip.id)}
                                className={`rounded-full border px-2.5 py-1 text-[10px] font-semibold transition ${
                                    activeFilter === chip.id
                                        ? 'border-slate-500 bg-slate-800 text-white'
                                        : 'border-slate-800 text-slate-500 hover:border-slate-700 hover:text-slate-300'
                                }`}
                            >
                                {chip.label} ({chip.count})
                            </button>
                        ))}
                    </div>

                    <div className="flex flex-wrap gap-2 border-t border-slate-800/50 px-4 py-2.5">
                        <button
                            type="button"
                            disabled={bulkProcessing || filteredIncidents.length === 0}
                            onClick={acknowledgeAllVisible}
                            className="rounded-lg border border-amber-500/25 px-2.5 py-1.5 text-[10px] font-semibold text-amber-300 transition hover:bg-amber-500/10 disabled:opacity-50"
                        >
                            Acknowledge all visible
                        </button>
                        <button
                            type="button"
                            disabled={bulkProcessing || selectedIds.size === 0}
                            onClick={resolveSelected}
                            className="rounded-lg border border-emerald-500/25 px-2.5 py-1.5 text-[10px] font-semibold text-emerald-300 transition hover:bg-emerald-500/10 disabled:opacity-50"
                        >
                            Resolve selected ({selectedIds.size})
                        </button>
                        <button
                            type="button"
                            onClick={expandAll}
                            className="rounded-lg border border-slate-800 px-2.5 py-1.5 text-[10px] font-semibold text-slate-400 transition hover:bg-slate-800/40 hover:text-white"
                        >
                            Expand all
                        </button>
                        <button
                            type="button"
                            onClick={collapseAll}
                            className="rounded-lg border border-slate-800 px-2.5 py-1.5 text-[10px] font-semibold text-slate-400 transition hover:bg-slate-800/40 hover:text-white"
                        >
                            Collapse all
                        </button>
                    </div>

                    <div className="space-y-2 px-4 pb-4">
                        {paginatedGroups.length === 0 ? (
                            <div className="rounded-xl border border-slate-800/80 bg-slate-950/30 px-4 py-8 text-center text-xs text-slate-500">
                                No incidents match this filter.
                            </div>
                        ) : (
                            paginatedGroups.map((group) => (
                                <AttackGroupCard
                                    key={group.key}
                                    group={group}
                                    nowTick={nowTick}
                                    incidentActionId={incidentActionId}
                                    expanded={expandedGroups.has(group.key)}
                                    expandedSites={expandedSites}
                                    siteVisibleCount={siteVisibleCounts[group.key] ?? SITES_INITIAL_VISIBLE}
                                    selectedIds={selectedIds}
                                    siteIncidentPages={siteIncidentPages}
                                    onToggleGroup={() => toggleGroup(group.key)}
                                    onToggleSite={toggleSite}
                                    onShowMoreSites={() => {
                                        setSiteVisibleCounts((current) => ({
                                            ...current,
                                            [group.key]: (current[group.key] ?? SITES_INITIAL_VISIBLE) + SITES_LOAD_MORE_STEP,
                                        }));
                                    }}
                                    onToggleSelect={toggleSelect}
                                    onSiteIncidentPageChange={(siteKey, page) => {
                                        setSiteIncidentPages((current) => ({ ...current, [siteKey]: page }));
                                    }}
                                    onInvestigate={onInvestigate}
                                    onAcknowledge={onAcknowledge}
                                    onResolve={onResolve}
                                    onOpenDrawer={onOpenDrawer}
                                />
                            ))
                        )}
                    </div>

                    <ListPagination
                        page={groupPage}
                        totalPages={groupTotalPages}
                        totalItems={attackGroups.length}
                        pageSize={GROUPS_PER_PAGE}
                        onPageChange={setGroupPage}
                    />
                </div>
            ) : null}
        </section>
    );
}
