"use client";

import { useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { Badge, Button, Card } from "@/components/ui";
import { api, vulnerabilities, type Severity, type VulnAlertRule } from "@/lib/api";
import { SEVERITY_ORDER, SeverityBadge } from "./SeverityVisuals";

/*
 * Alert rules live beside the channels they consume.
 *
 * A rule fires once per scan, not once per finding: the scheduler batches a
 * whole tick into one digest, which is what stops a database refresh opening
 * five hundred findings and sending five hundred messages.
 */

const inputClass =
    "w-full rounded-lg border border-border bg-surface-2 px-3 py-2 text-sm text-text-primary placeholder:text-text-tertiary focus:border-accent/50 focus:outline-none focus:ring-1 focus:ring-accent/30";
const labelClass = "mb-1.5 block text-sm font-medium text-text-secondary";

export function VulnAlertRulesCard() {
    const qc = useQueryClient();
    const [adding, setAdding] = useState(false);

    const rules = useQuery({ queryKey: ["vuln-rules"], queryFn: () => vulnerabilities.listRules() });
    const channels = useQuery({ queryKey: ["channels"], queryFn: () => api.listChannels() });

    const invalidate = () => qc.invalidateQueries({ queryKey: ["vuln-rules"] });

    const remove = useMutation({
        mutationFn: (id: string) => vulnerabilities.deleteRule(id),
        onSuccess: invalidate,
    });

    const toggle = useMutation({
        mutationFn: (r: VulnAlertRule) =>
            vulnerabilities.updateRule(r.id, {
                name: r.name,
                enabled: !r.enabled,
                min_severity: r.min_severity,
                tags: r.tags,
                channel_ids: r.channel_ids,
            }),
        onSuccess: invalidate,
    });

    const channelName = (id: string) => channels.data?.find((c) => c.channel_id === id)?.name ?? id;

    return (
        <Card>
            <div className="mb-4 flex items-start justify-between gap-3">
                <div>
                    <h2 className="text-base font-bold tracking-[-0.02em] text-text-primary">Vulnerability alerts</h2>
                    <p className="mt-0.5 text-sm text-text-secondary">
                        One digest per rule per scan, summarising what newly opened — never one message per finding.
                    </p>
                </div>
                {!adding && (
                    <Button size="sm" variant="secondary" onClick={() => setAdding(true)}>
                        New rule
                    </Button>
                )}
            </div>

            {adding && <RuleForm onDone={() => setAdding(false)} />}

            {rules.isLoading ? (
                <p className="text-sm text-text-secondary">Loading…</p>
            ) : !rules.data || rules.data.length === 0 ? (
                <p className="text-sm text-text-secondary">
                    No rules yet. Without one, findings appear on the board but nobody is told about them.
                </p>
            ) : (
                <ul className="divide-y divide-border-soft">
                    {rules.data.map((r) => (
                        <li key={r.id} className="flex flex-wrap items-center gap-3 py-3">
                            <span className="text-sm font-medium text-text-primary">{r.name}</span>
                            <Badge variant={r.enabled ? "success" : "neutral"}>{r.enabled ? "enabled" : "disabled"}</Badge>
                            <span className="flex items-center gap-1.5 text-xs text-text-secondary">
                                at or above <SeverityBadge severity={r.min_severity} />
                            </span>
                            {r.tags && Object.keys(r.tags).length > 0 && (
                                <span className="font-mono text-xs text-text-tertiary">
                                    {Object.entries(r.tags)
                                        .map(([k, v]) => `${k}:${v}`)
                                        .join(" ")}
                                </span>
                            )}
                            <span className="text-xs text-text-tertiary">→ {r.channel_ids.map(channelName).join(", ")}</span>
                            <div className="ml-auto flex gap-2">
                                <Button size="sm" variant="ghost" onClick={() => toggle.mutate(r)}>
                                    {r.enabled ? "Disable" : "Enable"}
                                </Button>
                                <Button size="sm" variant="ghost" onClick={() => remove.mutate(r.id)}>
                                    Delete
                                </Button>
                            </div>
                        </li>
                    ))}
                </ul>
            )}
        </Card>
    );
}

function RuleForm({ onDone }: { onDone: () => void }) {
    const qc = useQueryClient();
    const channels = useQuery({ queryKey: ["channels"], queryFn: () => api.listChannels() });

    const [name, setName] = useState("");
    const [minSeverity, setMinSeverity] = useState<Severity>("high");
    const [selected, setSelected] = useState<string[]>([]);
    const [tags, setTags] = useState("");

    const create = useMutation({
        mutationFn: () =>
            vulnerabilities.createRule({
                name: name.trim(),
                enabled: true,
                min_severity: minSeverity,
                tags: parseTags(tags),
                channel_ids: selected,
            }),
        onSuccess: () => {
            qc.invalidateQueries({ queryKey: ["vuln-rules"] });
            onDone();
        },
    });

    const canSave = name.trim().length > 0 && selected.length > 0 && !create.isPending;

    return (
        <div className="mb-5 space-y-3 rounded-lg border border-border bg-surface-2 p-4">
            <div>
                <label className={labelClass}>Name</label>
                <input className={inputClass} value={name} onChange={(e) => setName(e.target.value)} placeholder="Production criticals" />
            </div>

            <div>
                <label className={labelClass}>Minimum severity</label>
                <select className={inputClass} value={minSeverity} onChange={(e) => setMinSeverity(e.target.value as Severity)}>
                    {SEVERITY_ORDER.map((s) => (
                        <option key={s} value={s}>
                            {s}
                        </option>
                    ))}
                </select>
            </div>

            <div>
                <label className={labelClass}>Server tags (optional)</label>
                <input className={inputClass} value={tags} onChange={(e) => setTags(e.target.value)} placeholder="env:prod role:web" />
                <p className="mt-1 text-xs text-text-tertiary">
                    Space-separated key:value pairs. Resolved the same way a workflow resolves its targets.
                </p>
            </div>

            <div>
                <label className={labelClass}>Channels</label>
                <div className="space-y-1">
                    {channels.data?.map((c) => (
                        <label key={c.channel_id} className="flex items-center gap-2 text-sm text-text-secondary">
                            <input
                                type="checkbox"
                                checked={selected.includes(c.channel_id)}
                                onChange={(e) =>
                                    setSelected((prev) => (e.target.checked ? [...prev, c.channel_id] : prev.filter((id) => id !== c.channel_id)))
                                }
                            />
                            {c.name} <span className="text-text-tertiary">({c.type})</span>
                        </label>
                    ))}
                    {channels.data && channels.data.length === 0 && (
                        <p className="text-xs text-text-tertiary">No channels configured yet. A rule needs at least one.</p>
                    )}
                </div>
            </div>

            {create.error && <p className="text-sm text-danger">{(create.error as Error).message}</p>}

            <div className="flex justify-end gap-2">
                <Button size="sm" variant="secondary" onClick={onDone}>
                    Cancel
                </Button>
                <Button size="sm" disabled={!canSave} loading={create.isPending} onClick={() => create.mutate()}>
                    Create
                </Button>
            </div>
        </div>
    );
}

/** parseTags reads "env:prod role:web" into a map. A pair without a colon is
 *  dropped rather than guessed at. */
function parseTags(raw: string): Record<string, string> | undefined {
    const out: Record<string, string> = {};
    for (const part of raw.split(/\s+/)) {
        const idx = part.indexOf(":");
        if (idx <= 0) continue;
        out[part.slice(0, idx)] = part.slice(idx + 1);
    }
    return Object.keys(out).length > 0 ? out : undefined;
}
