"use client";

import { useState } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { useParams, useRouter } from "next/navigation";
import Link from "next/link";
import { api, Incident, Rollup } from "@/lib/api";
import { Button } from "@/components/ui";
import {
    Slot,
    StatusChip,
    avgLatency,
    buildSlots,
    displayStatus,
    formatDuration,
    formatMs,
    formatPct,
    relativeTime,
    statusStripe,
    targetSummary,
    uptimePct,
} from "@/components/monitors/MonitorVisuals";

/*
 * Hourly uptime and response time share one time axis, because the question
 * people actually arrive with is whether the slow hour and the failing hour
 * are the same hour. The incidents below are the same story told in words.
 */

const CHART_W = 480;
const CHART_H = 158;

function niceCeiling(ms: number): number {
    if (ms <= 0) return 100;
    const steps = [50, 100, 250, 500, 1000, 2500, 5000, 10000, 30000];
    return steps.find((s) => s >= ms) ?? Math.ceil(ms / 10000) * 10000;
}

function History({ slots }: { slots: Slot[] }) {
    const latencies = slots.map((s) => s.latency).filter((v): v is number => v !== null);
    const scale = niceCeiling(Math.max(...latencies, 0) * 1.15);

    /*
     * The trace breaks over hours with no checks rather than drawing a
     * straight line across them — a line implies data that was never
     * collected.
     */
    const segments: string[] = [];
    let open: string[] = [];
    slots.forEach((s, i) => {
        if (s.latency === null) {
            if (open.length > 1) segments.push(open.join(" "));
            open = [];
            return;
        }
        const x = (i / Math.max(slots.length - 1, 1)) * CHART_W;
        const y = CHART_H - Math.min(s.latency / scale, 1) * CHART_H;
        open.push(`${open.length === 0 ? "M" : "L"}${x.toFixed(1)} ${y.toFixed(1)}`);
    });
    if (open.length > 1) segments.push(open.join(" "));

    const firstAt = slots[0]?.at;
    const midAt = slots[Math.floor(slots.length / 2)]?.at;
    const tick = (d?: Date) => (d ? d.toLocaleString(undefined, { weekday: "short", hour: "2-digit", minute: "2-digit" }) : "");

    return (
        <div>
            <div className="relative h-[190px] overflow-hidden rounded-sm bg-well px-2.5 pb-6 pt-2.5">
                {[1, 0.5].map((f) => (
                    <div key={f} className="pointer-events-none absolute left-2.5 right-2.5 border-t border-dashed border-border-soft" style={{ top: `${10 + (1 - f) * CHART_H}px` }}>
                        <span className="absolute right-0 -top-[11px] bg-well pl-1.5 font-mono text-[9px] text-text-tertiary">{formatMs(scale * f)}</span>
                    </div>
                ))}

                <div className="absolute inset-x-2.5 bottom-6 top-2.5 flex items-end gap-0.5">
                    {slots.map((s) => (
                        <div
                            key={s.at.getTime()}
                            className="h-full flex-1"
                            title={s.pct === null ? "no checks ran" : `${s.pct.toFixed(1)}% up`}
                            style={{ display: "flex", alignItems: "flex-end" }}
                        >
                            <div
                                className={`w-full rounded-[1px] ${s.pct === null ? "bg-border-soft" : s.pct >= 99.5 ? "bg-success/60" : s.pct >= 80 ? "bg-warning/70" : "bg-danger/80"}`}
                                style={{ height: s.pct === null ? "18%" : `${Math.max(s.pct, 12)}%` }}
                            />
                        </div>
                    ))}
                </div>

                <svg
                    className="absolute inset-x-2.5 bottom-6 top-2.5 h-[calc(100%-2rem)] w-[calc(100%-1.25rem)]"
                    viewBox={`0 0 ${CHART_W} ${CHART_H}`}
                    preserveAspectRatio="none"
                    aria-hidden
                >
                    {segments.map((d, i) => (
                        <path key={i} d={d} fill="none" stroke="rgb(var(--accent-rgb))" strokeWidth={1.5} vectorEffect="non-scaling-stroke" />
                    ))}
                </svg>

                <div className="absolute inset-x-2.5 bottom-1 flex justify-between font-mono text-[10px] text-text-tertiary">
                    <span>{tick(firstAt)}</span>
                    <span>{tick(midAt)}</span>
                    <span>now</span>
                </div>
            </div>

            <div className="mt-3 flex flex-wrap gap-4 text-[11.5px] text-text-secondary">
                <span className="flex items-center gap-2">
                    <span className="block h-2.5 w-2.5 rounded-sm bg-success/60" /> Hourly uptime
                </span>
                <span className="flex items-center gap-2">
                    <span className="block h-0.5 w-3.5 bg-accent" /> Response time
                </span>
                <span className="text-text-tertiary">Gaps mean no checks ran</span>
            </div>
        </div>
    );
}

function Figure({ label, value, unit, tone = "" }: { label: string; value: string; unit?: string; tone?: string }) {
    return (
        <div className="border-l border-border-soft px-5 py-3.5 first:border-l-0">
            <p className="font-mono text-[10px] uppercase tracking-[0.16em] text-text-tertiary">{label}</p>
            <p className={`mt-1 font-mono text-xl font-semibold tabular-nums tracking-tight ${tone || "text-text-primary"}`}>
                {value}
                {unit && <span className="text-xs font-normal text-text-tertiary">{unit}</span>}
            </p>
        </div>
    );
}

function IncidentRow({ incident }: { incident: Incident }) {
    const open = !incident.resolved_at;
    const started = new Date(incident.started_at);
    return (
        <div className="grid grid-cols-[14px_minmax(0,1fr)] items-start gap-3 border-t border-border-soft px-5 py-3 first:border-t-0">
            <span className={`mt-1.5 block h-2 w-2 rounded-full ${open ? "bg-danger ring-4 ring-danger/20" : "bg-text-tertiary"}`} />
            <div className="min-w-0">
                <p className="text-[13.5px] text-text-primary">{incident.cause || "Check failed"}</p>
                <p className="mt-1 flex flex-wrap gap-2 font-mono text-[11px] text-text-tertiary">
                    <span>
                        {started.toLocaleString(undefined, { weekday: "short", hour: "2-digit", minute: "2-digit" })}
                        {incident.resolved_at && ` → ${new Date(incident.resolved_at).toLocaleString(undefined, { hour: "2-digit", minute: "2-digit" })}`}
                    </span>
                    <span className="text-border">·</span>
                    <span className="text-text-secondary">
                        {open ? "Ongoing, " : ""}
                        {formatDuration(incident.started_at, incident.resolved_at)}
                    </span>
                </p>
            </div>
        </div>
    );
}

function Panel({ title, aside, children, padded = true }: { title: string; aside?: string; children: React.ReactNode; padded?: boolean }) {
    return (
        <div className="rounded-lg border border-border bg-surface">
            <div className="flex items-baseline justify-between gap-3 border-b border-border-soft px-5 py-3.5">
                <h2 className="text-[15px] font-semibold text-text-primary">{title}</h2>
                {aside && <span className="font-mono text-[10px] uppercase tracking-[0.16em] text-text-tertiary">{aside}</span>}
            </div>
            <div className={padded ? "p-5" : ""}>{children}</div>
        </div>
    );
}

function Row({ label, value }: { label: string; value: React.ReactNode }) {
    return (
        <div className="flex justify-between gap-3 border-t border-border-soft py-2.5 first:border-t-0 first:pt-0">
            <dt className="text-text-tertiary">{label}</dt>
            <dd className="break-all text-right font-mono text-text-primary">{value}</dd>
        </div>
    );
}

export default function MonitorDetailPage() {
    const params = useParams();
    const router = useRouter();
    const queryClient = useQueryClient();
    const monitorId = params.id as string;
    const [confirmDelete, setConfirmDelete] = useState(false);

    const { data: monitor, isLoading } = useQuery({
        queryKey: ["monitors", monitorId],
        queryFn: () => api.getMonitor(monitorId),
        refetchInterval: 30_000,
    });

    const { data: rollups } = useQuery({
        queryKey: ["monitors", monitorId, "uptime"],
        queryFn: () => api.getMonitorUptime(monitorId),
        refetchInterval: 60_000,
    });

    const { data: incidents } = useQuery({
        queryKey: ["monitors", monitorId, "incidents"],
        queryFn: () => api.getMonitorIncidents(monitorId),
        refetchInterval: 60_000,
    });

    const { data: channels } = useQuery({
        queryKey: ["channels"],
        queryFn: () => api.listChannels(),
        enabled: (monitor?.channel_ids?.length ?? 0) > 0,
    });

    const { data: servers } = useQuery({
        queryKey: ["servers"],
        queryFn: () => api.listServers(),
        enabled: !!monitor && monitor.runner !== "server",
    });

    const { mutate: deleteMonitor, isPending: isDeleting } = useMutation({
        mutationFn: () => api.deleteMonitor(monitorId),
        onSuccess: () => {
            queryClient.invalidateQueries({ queryKey: ["monitors"] });
            router.push("/monitors");
        },
    });

    const { mutate: toggleEnabled, isPending: isToggling } = useMutation({
        mutationFn: (enabled: boolean) => api.updateMonitor(monitorId, { enabled }),
        onSuccess: () => queryClient.invalidateQueries({ queryKey: ["monitors", monitorId] }),
    });

    if (isLoading) {
        return (
            <div className="flex h-full items-center justify-center">
                <div className="h-8 w-8 animate-spin rounded-full border-2 border-border border-t-accent" />
            </div>
        );
    }

    if (!monitor) {
        return (
            <div className="p-4 sm:p-6 lg:p-8">
                <div className="rounded-lg border border-danger/30 bg-danger/10 p-4 text-danger">
                    That monitor no longer exists.{" "}
                    <Link href="/monitors" className="underline">
                        Back to monitors
                    </Link>
                    .
                </div>
            </div>
        );
    }

    const all: Rollup[] = rollups ?? [];
    const slots = buildSlots(all);
    const status = displayStatus(monitor);
    const pct24 = uptimePct(all.slice(-24));
    const pct30d = uptimePct(all);
    const latency = monitor.state.latency_ms > 0 ? monitor.state.latency_ms : avgLatency(all.slice(-1));

    const certDays = monitor.state.cert_expiry_at
        ? Math.round((new Date(monitor.state.cert_expiry_at).getTime() - Date.now()) / 86400_000)
        : null;

    const openIncidents = (incidents ?? []).filter((i) => !i.resolved_at).length;
    const runnerName =
        monitor.runner === "server" ? "Control plane" : servers?.find((s) => s.server_id === monitor.runner)?.hostname || monitor.runner;
    const alertChannels = (monitor.channel_ids ?? []).map((id) => channels?.find((c) => c.channel_id === id));

    return (
        <div className="p-4 sm:p-6 lg:p-8">
            <Link href="/monitors" className="mb-2.5 inline-block text-sm text-text-secondary hover:text-text-primary">
                ← Monitors
            </Link>

            <div className="mb-5 flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
                <div className="min-w-0">
                    <div className="flex flex-wrap items-center gap-2.5">
                        <h1 className="text-2xl font-bold tracking-tight text-text-primary">{monitor.name}</h1>
                        <StatusChip status={status} />
                        <span className="rounded-sm border border-border px-1.5 font-mono text-[10px] uppercase tracking-[0.1em] text-text-secondary">
                            {monitor.type}
                        </span>
                    </div>
                    <p className="mt-1.5 break-all font-mono text-xs text-text-tertiary">{targetSummary(monitor)}</p>
                    {monitor.state.message && <p className="mt-1.5 text-sm text-text-secondary">{monitor.state.message}</p>}
                </div>
                <div className="flex flex-wrap gap-2">
                    <Link href={`/monitors/${monitorId}/edit`}>
                        <Button variant="secondary">Edit</Button>
                    </Link>
                    <Button variant="secondary" loading={isToggling} onClick={() => toggleEnabled(!monitor.enabled)}>
                        {monitor.enabled ? "Pause checks" : "Resume checks"}
                    </Button>
                    {!confirmDelete ? (
                        <Button variant="danger" onClick={() => setConfirmDelete(true)}>
                            Delete
                        </Button>
                    ) : (
                        <div className="flex items-center gap-2">
                            <span className="text-sm text-danger">Delete this monitor and its history?</span>
                            <Button variant="danger" loading={isDeleting} onClick={() => deleteMonitor()}>
                                Delete
                            </Button>
                            <Button variant="ghost" onClick={() => setConfirmDelete(false)}>
                                Keep
                            </Button>
                        </div>
                    )}
                </div>
            </div>

            <div className="grid grid-cols-1 items-start gap-5 lg:grid-cols-[minmax(0,1fr)_300px]">
                <div className="flex flex-col gap-5">
                    <div className="rounded-lg border border-border bg-surface">
                        <div className="flex items-baseline justify-between gap-3 border-b border-border-soft px-5 py-3.5">
                            <h2 className="text-[15px] font-semibold text-text-primary">Last 48 hours</h2>
                            <span className="font-mono text-[10px] uppercase tracking-[0.16em] text-text-tertiary">1 hour per bar</span>
                        </div>
                        <div className="p-5">
                            <History slots={slots} />
                        </div>
                        <div className="grid grid-cols-2 border-t border-border-soft sm:grid-cols-4">
                            <Figure
                                label="Uptime 24h"
                                value={formatPct(pct24)}
                                unit={pct24 !== null ? "%" : undefined}
                                tone={pct24 !== null && pct24 < 99 ? "text-danger" : ""}
                            />
                            <Figure label="Uptime 30d" value={formatPct(pct30d)} unit={pct30d !== null ? "%" : undefined} />
                            <Figure
                                label="Response now"
                                value={status === "down" ? "—" : formatMs(latency)}
                                tone={status === "down" ? "text-danger" : ""}
                            />
                            <Figure
                                label="Certificate"
                                value={certDays === null ? "n/a" : `${certDays}`}
                                unit={certDays === null ? undefined : certDays === 1 ? " day left" : " days left"}
                                tone={certDays !== null && certDays <= (monitor.target.tls_warn_days ?? 14) ? "text-warning" : ""}
                            />
                        </div>
                    </div>

                    <Panel
                        title="Incidents"
                        aside={incidents && incidents.length > 0 ? `${incidents.length} recorded${openIncidents ? ` · ${openIncidents} open` : ""}` : undefined}
                        padded={false}
                    >
                        {!incidents || incidents.length === 0 ? (
                            <p className="px-5 py-12 text-center text-sm text-text-secondary">
                                No incidents recorded. Every check has passed since this monitor was created.
                            </p>
                        ) : (
                            incidents.map((inc) => <IncidentRow key={inc.incident_id} incident={inc} />)
                        )}
                    </Panel>
                </div>

                <div className="flex flex-col gap-5">
                    <Panel title="Check">
                        <dl className="text-[13px]">
                            <Row label="Runs from" value={runnerName} />
                            <Row label="Every" value={`${monitor.interval_sec} s`} />
                            <Row label="Fails after" value={`${monitor.retries} ${monitor.retries === 1 ? "try" : "tries"}`} />
                            {monitor.type === "http" && monitor.target.method && <Row label="Method" value={monitor.target.method} />}
                            {monitor.type === "http" && monitor.target.expected_status && (
                                <Row label="Expects" value={monitor.target.expected_status} />
                            )}
                            {monitor.target.keyword && <Row label="Body contains" value={monitor.target.keyword} />}
                            {monitor.type === "tls" && <Row label="Warns at" value={`${monitor.target.tls_warn_days ?? 14} days`} />}
                            <Row label="Last checked" value={relativeTime(monitor.state.last_check_at)} />
                        </dl>
                    </Panel>

                    <Panel title="Alerts">
                        {alertChannels.length === 0 ? (
                            <p className="text-sm text-text-secondary">No one is told when this check fails.</p>
                        ) : (
                            <dl className="text-[13px]">
                                {alertChannels.map((c, i) => (
                                    <Row
                                        key={monitor.channel_ids?.[i]}
                                        label={c ? c.type : "channel"}
                                        value={c ? c.name : "Removed channel"}
                                    />
                                ))}
                            </dl>
                        )}
                        <Link href="/settings/notifications">
                            <Button variant="secondary" size="sm" className="mt-4">
                                Manage channels
                            </Button>
                        </Link>
                    </Panel>

                    <div className="rounded-lg border border-border bg-surface px-5 py-4">
                        <div className="flex items-center gap-2.5">
                            <span className={`block h-2 w-2 rounded-full ${statusStripe[status]}`} />
                            <p className="text-[13px] text-text-secondary">
                                {status === "paused"
                                    ? "Paused — no checks are running."
                                    : status === "down"
                                      ? `Failing for ${monitor.state.fails} consecutive ${monitor.state.fails === 1 ? "check" : "checks"}.`
                                      : `Checked ${relativeTime(monitor.state.last_check_at)}.`}
                            </p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    );
}
