'use client';

import { useCallback, useEffect, useState } from 'react';
import {
    Building2,
    Pencil,
    Plus,
    Trash2,
    ChevronDown,
    ChevronRight,
    Link2,
} from 'lucide-react';
import { Button, IconButton, Input, Card, Dialog } from '@/components/ui';

interface Vendor {
    id: number;
    name: string;
    promisedUptime: number;
    contractRef: string | null;
    creditTerms: string | null;
    notes: string | null;
    _count?: { monitors: number };
}

interface LayerAttribution {
    byLayer: Record<string, number>;
    unattributed: number;
}

interface MonitorSlo {
    monitorId: number;
    name: string;
    slo: { sli: number };
}

interface VendorSummary {
    measuredUptime: number;
    attainment: number;
    meetingSla: boolean;
    errorBudgetRemainingPercent: number;
    breaches: number;
    mttrMinutes: number;
    creditPercentEstimate: number | null;
    windowDays: number;
    attribution: LayerAttribution;
    monitors: MonitorSlo[];
}

interface MonitorLite {
    id: number;
    name: string;
}

const pct = (n: number) => `${n.toFixed(2)}%`;
const emptyForm = (): Omit<Vendor, 'id' | '_count'> => ({
    name: '',
    promisedUptime: 99.9,
    contractRef: '',
    creditTerms: '',
    notes: '',
});

export function VendorList({
    canWrite,
    title = 'Vendors',
    subtitle = "Track each vendor's SLA against the uptime they promised.",
}: {
    canWrite: boolean;
    title?: string;
    subtitle?: string;
}) {
    const [vendors, setVendors] = useState<Vendor[]>([]);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState<string | null>(null);

    // expand → SLA scorecard
    const [expanded, setExpanded] = useState<number | null>(null);
    const [summaries, setSummaries] = useState<Record<number, VendorSummary | 'loading'>>({});

    // create / edit dialog
    const [formOpen, setFormOpen] = useState(false);
    const [editing, setEditing] = useState<Vendor | null>(null);
    const [form, setForm] = useState(emptyForm());
    const [saving, setSaving] = useState(false);

    // delete confirm
    const [deleteTarget, setDeleteTarget] = useState<Vendor | null>(null);

    // assign monitors dialog
    const [assignFor, setAssignFor] = useState<Vendor | null>(null);
    const [allMonitors, setAllMonitors] = useState<MonitorLite[]>([]);
    const [selectedMonitorIds, setSelectedMonitorIds] = useState<Set<number>>(new Set());
    const [assignSaving, setAssignSaving] = useState(false);

    const fetchVendors = useCallback(async () => {
        setLoading(true);
        try {
            const res = await fetch('/api/vendors');
            if (!res.ok) throw new Error('Failed to load vendors');
            const data = await res.json();
            setVendors(data.vendors ?? []);
            setError(null);
        } catch (e) {
            setError((e as Error).message);
        } finally {
            setLoading(false);
        }
    }, []);

    useEffect(() => {
        fetchVendors();
    }, [fetchVendors]);

    async function toggleExpand(v: Vendor) {
        if (expanded === v.id) {
            setExpanded(null);
            return;
        }
        setExpanded(v.id);
        if (!summaries[v.id]) {
            setSummaries((s) => ({ ...s, [v.id]: 'loading' }));
            try {
                const res = await fetch(`/api/vendors/${v.id}`);
                const data = await res.json();
                setSummaries((s) => ({ ...s, [v.id]: data.summary as VendorSummary }));
            } catch {
                setSummaries((s) => {
                    const next = { ...s };
                    delete next[v.id];
                    return next;
                });
            }
        }
    }

    function openCreate() {
        setEditing(null);
        setForm(emptyForm());
        setFormOpen(true);
    }
    function openEdit(v: Vendor) {
        setEditing(v);
        setForm({
            name: v.name,
            promisedUptime: v.promisedUptime,
            contractRef: v.contractRef ?? '',
            creditTerms: v.creditTerms ?? '',
            notes: v.notes ?? '',
        });
        setFormOpen(true);
    }

    async function saveForm() {
        setSaving(true);
        try {
            const url = editing ? `/api/vendors/${editing.id}` : '/api/vendors';
            const method = editing ? 'PUT' : 'POST';
            const res = await fetch(url, {
                method,
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    ...form,
                    promisedUptime: Number(form.promisedUptime),
                    contractRef: form.contractRef || null,
                    creditTerms: form.creditTerms || null,
                    notes: form.notes || null,
                }),
            });
            if (!res.ok) throw new Error('Save failed');
            setFormOpen(false);
            await fetchVendors();
        } catch (e) {
            setError((e as Error).message);
        } finally {
            setSaving(false);
        }
    }

    async function confirmDelete() {
        if (!deleteTarget) return;
        try {
            await fetch(`/api/vendors/${deleteTarget.id}`, { method: 'DELETE' });
            setDeleteTarget(null);
            await fetchVendors();
        } catch (e) {
            setError((e as Error).message);
        }
    }

    async function openAssign(v: Vendor) {
        setAssignFor(v);
        setAssignSaving(false);
        // all monitors for the picker
        try {
            const [monRes, detailRes] = await Promise.all([
                fetch('/api/monitors?limit=500'),
                fetch(`/api/vendors/${v.id}`),
            ]);
            const monData = await monRes.json();
            const detail = await detailRes.json();
            setAllMonitors((monData.monitors ?? []).map((m: { id: number; name: string }) => ({ id: m.id, name: m.name })));
            const assigned: number[] = (detail.summary?.monitors ?? []).map((m: MonitorSlo) => m.monitorId);
            setSelectedMonitorIds(new Set(assigned));
        } catch {
            setAllMonitors([]);
            setSelectedMonitorIds(new Set());
        }
    }

    async function saveAssign() {
        if (!assignFor) return;
        setAssignSaving(true);
        try {
            await fetch(`/api/vendors/${assignFor.id}/monitors`, {
                method: 'PUT',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ monitorIds: Array.from(selectedMonitorIds) }),
            });
            // bust the cached summary so the scorecard re-fetches with new members
            setSummaries((s) => {
                const next = { ...s };
                delete next[assignFor.id];
                return next;
            });
            setAssignFor(null);
            await fetchVendors();
        } catch (e) {
            setError((e as Error).message);
        } finally {
            setAssignSaving(false);
        }
    }

    return (
        <div>
            <div className="mb-6 flex items-center justify-between gap-3">
                <div>
                    <h1 className="flex items-center gap-2 text-2xl font-bold text-fg">
                        <Building2 className="size-6 text-brand" /> {title}
                    </h1>
                    <p className="mt-1 text-sm text-muted">{subtitle}</p>
                </div>
                {canWrite ? (
                    <Button onClick={openCreate}>
                        <Plus className="size-4" /> Add vendor
                    </Button>
                ) : null}
            </div>

            {error ? (
                <Card className="mb-4 border-danger">
                    <p className="text-sm text-danger">{error}</p>
                </Card>
            ) : null}

            {loading ? (
                <p className="text-sm text-muted">Loading vendors…</p>
            ) : vendors.length === 0 ? (
                <Card className="text-center">
                    <p className="text-sm text-muted">
                        No vendors yet.{canWrite ? ' Add one to start tracking SLA accountability.' : ' Add vendors in Settings → System.'}
                    </p>
                </Card>
            ) : (
                <div className="space-y-3">
                    {vendors.map((v) => {
                        const summary = summaries[v.id];
                        const isOpen = expanded === v.id;
                        return (
                            <Card key={v.id} className="p-0">
                                <div className="flex items-center gap-3 p-4">
                                    <IconButton
                                        label={isOpen ? 'Collapse SLA' : 'Expand SLA'}
                                        variant="ghost"
                                        size="sm"
                                        onClick={() => toggleExpand(v)}
                                    >
                                        {isOpen ? <ChevronDown className="size-4" /> : <ChevronRight className="size-4" />}
                                    </IconButton>
                                    <div className="min-w-0 flex-1">
                                        <div className="flex items-center gap-2">
                                            <span className="truncate font-semibold text-fg">{v.name}</span>
                                        </div>
                                        <p className="text-xs text-muted">
                                            Promised {pct(v.promisedUptime)} · {v._count?.monitors ?? 0} monitor
                                            {(v._count?.monitors ?? 0) === 1 ? '' : 's'}
                                        </p>
                                    </div>
                                    {canWrite ? (
                                        <div className="flex items-center gap-1">
                                            <IconButton label="Assign monitors" variant="ghost" size="sm" onClick={() => openAssign(v)}>
                                                <Link2 className="size-4" />
                                            </IconButton>
                                            <IconButton label="Edit vendor" variant="ghost" size="sm" onClick={() => openEdit(v)}>
                                                <Pencil className="size-4" />
                                            </IconButton>
                                            <IconButton label="Delete vendor" variant="danger" size="sm" onClick={() => setDeleteTarget(v)}>
                                                <Trash2 className="size-4" />
                                            </IconButton>
                                        </div>
                                    ) : null}
                                </div>

                                {isOpen ? (
                                    <div className="border-t border-border p-4">
                                        {summary === 'loading' || summary === undefined ? (
                                            <p className="text-sm text-muted">Computing SLA…</p>
                                        ) : (
                                            <VendorScorecard summary={summary} promised={v.promisedUptime} />
                                        )}
                                    </div>
                                ) : null}
                            </Card>
                        );
                    })}
                </div>
            )}

            {/* Create / Edit dialog */}
            {formOpen ? (
                <Dialog
                    isOpen={formOpen}
                    onClose={() => setFormOpen(false)}
                    title={editing ? 'Edit vendor' : 'Add vendor'}
                    footer={
                        <>
                            <Button variant="ghost" onClick={() => setFormOpen(false)}>
                                Cancel
                            </Button>
                            <Button onClick={saveForm} disabled={saving || !form.name.trim()}>
                                {saving ? 'Saving…' : editing ? 'Save' : 'Create'}
                            </Button>
                        </>
                    }
                >
                    <div className="flex flex-col gap-4">
                        <Input
                            label="Name"
                            value={form.name}
                            onChange={(e) => setForm((f) => ({ ...f, name: e.target.value }))}
                            placeholder="Cloudflare"
                        />
                        <Input
                            label="Promised uptime (%)"
                            type="number"
                            step="0.01"
                            value={String(form.promisedUptime)}
                            onChange={(e) => setForm((f) => ({ ...f, promisedUptime: parseFloat(e.target.value) }))}
                        />
                        <Input
                            label="Contract reference"
                            value={form.contractRef ?? ''}
                            onChange={(e) => setForm((f) => ({ ...f, contractRef: e.target.value }))}
                            placeholder="MSA-2026-014 (optional)"
                        />
                        <Input
                            label="Credit terms"
                            value={form.creditTerms ?? ''}
                            onChange={(e) => setForm((f) => ({ ...f, creditTerms: e.target.value }))}
                            hint="e.g. 10% credit if uptime < 99.9%"
                        />
                    </div>
                </Dialog>
            ) : null}

            {/* Delete confirm */}
            {deleteTarget ? (
                <Dialog
                    isOpen={!!deleteTarget}
                    onClose={() => setDeleteTarget(null)}
                    title="Delete vendor?"
                    footer={
                        <>
                            <Button variant="ghost" onClick={() => setDeleteTarget(null)}>
                                Cancel
                            </Button>
                            <Button variant="danger" onClick={confirmDelete}>
                                Delete
                            </Button>
                        </>
                    }
                >
                    <p className="text-sm text-muted">
                        Remove <span className="font-medium text-fg">{deleteTarget.name}</span>? Its monitors will be
                        unlinked (not deleted). This can&apos;t be undone.
                    </p>
                </Dialog>
            ) : null}

            {/* Assign monitors */}
            {assignFor ? (
                <Dialog
                    isOpen={!!assignFor}
                    onClose={() => setAssignFor(null)}
                    title={`Assign monitors — ${assignFor.name}`}
                    footer={
                        <>
                            <Button variant="ghost" onClick={() => setAssignFor(null)}>
                                Cancel
                            </Button>
                            <Button onClick={saveAssign} disabled={assignSaving}>
                                {assignSaving ? 'Saving…' : `Save (${selectedMonitorIds.size})`}
                            </Button>
                        </>
                    }
                >
                    <p className="mb-3 text-xs text-muted">
                        Each monitor has one primary vendor. Selecting here sets this vendor as their primary.
                    </p>
                    <div className="max-h-72 space-y-1 overflow-y-auto">
                        {allMonitors.length === 0 ? (
                            <p className="text-sm text-muted">No monitors available.</p>
                        ) : (
                            allMonitors.map((m) => {
                                const checked = selectedMonitorIds.has(m.id);
                                return (
                                    <label
                                        key={m.id}
                                        className="flex cursor-pointer items-center gap-3 rounded-md px-2 py-2 hover:bg-elevated"
                                    >
                                        <input
                                            type="checkbox"
                                            checked={checked}
                                            onChange={(e) =>
                                                setSelectedMonitorIds((prev) => {
                                                    const next = new Set(prev);
                                                    if (e.target.checked) next.add(m.id);
                                                    else next.delete(m.id);
                                                    return next;
                                                })
                                            }
                                            className="size-4 accent-brand"
                                        />
                                        <span className="text-sm text-fg">{m.name}</span>
                                    </label>
                                );
                            })
                        )}
                    </div>
                </Dialog>
            ) : null}
        </div>
    );
}

function VendorScorecard({ summary, promised }: { summary: VendorSummary; promised: number }) {
    const layers = Object.entries(summary.attribution?.byLayer ?? {}).filter(([, n]) => n > 0);
    const totalAttr = layers.reduce((s, [, n]) => s + n, 0) + (summary.attribution?.unattributed ?? 0);
    return (
        <div className="flex flex-col gap-4">
            <div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
                <Stat
                    label={`Uptime (${summary.windowDays}d)`}
                    value={pct(summary.measuredUptime)}
                    tone={summary.meetingSla ? 'up' : 'down'}
                />
                <Stat
                    label="Attainment"
                    value={`${summary.attainment >= 0 ? '+' : ''}${summary.attainment.toFixed(2)} pts`}
                    tone={summary.meetingSla ? 'up' : 'down'}
                />
                <Stat
                    label="Error budget left"
                    value={`${Math.round(summary.errorBudgetRemainingPercent)}%`}
                    tone={summary.errorBudgetRemainingPercent < 0 ? 'down' : 'fg'}
                />
                <Stat label="Breaches" value={String(summary.breaches)} tone={summary.breaches > 0 ? 'down' : 'fg'} />
                <Stat label="MTTR" value={`${summary.mttrMinutes} min`} tone="fg" />
                <Stat label="Promised" value={pct(promised)} tone="fg" />
                <Stat
                    label="Est. credit"
                    value={summary.creditPercentEstimate == null ? '—' : `${summary.creditPercentEstimate}%`}
                    tone={summary.creditPercentEstimate ? 'down' : 'fg'}
                />
            </div>

            {totalAttr > 0 ? (
                <div>
                    <p className="mb-1 text-xs font-medium uppercase tracking-wider text-muted">Downtime by layer</p>
                    <div className="flex flex-wrap gap-2">
                        {layers.map(([layer, n]) => (
                            <span key={layer} className="rounded-full bg-elevated px-2.5 py-1 text-xs text-fg">
                                {layer}: {Math.round((n / totalAttr) * 100)}%
                            </span>
                        ))}
                        {summary.attribution?.unattributed > 0 ? (
                            <span className="rounded-full bg-elevated px-2.5 py-1 text-xs text-muted">
                                unattributed: {Math.round((summary.attribution.unattributed / totalAttr) * 100)}%
                            </span>
                        ) : null}
                    </div>
                </div>
            ) : null}

            <div>
                <p className="mb-1 text-xs font-medium uppercase tracking-wider text-muted">Monitors</p>
                {summary.monitors.length === 0 ? (
                    <p className="text-sm text-muted">No monitors assigned yet.</p>
                ) : (
                    <div className="flex flex-col gap-1">
                        {summary.monitors.map((m) => (
                            <div key={m.monitorId} className="flex items-center justify-between text-sm">
                                <span className="text-fg">{m.name}</span>
                                <span className="text-muted">{pct(m.slo.sli)}</span>
                            </div>
                        ))}
                    </div>
                )}
            </div>
        </div>
    );
}

function Stat({ label, value, tone }: { label: string; value: string; tone: 'fg' | 'up' | 'down' }) {
    const color = tone === 'up' ? 'text-up' : tone === 'down' ? 'text-down' : 'text-fg';
    return (
        <div className="rounded-lg bg-elevated px-3 py-2">
            <p className="text-xs text-muted">{label}</p>
            <p className={`text-lg font-semibold ${color}`}>{value}</p>
        </div>
    );
}
