"use client";

import { useEffect, useMemo, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { Button, Card } from "@/components/ui";
import { workloads, type Workload, type WorkloadAction, type WorkloadKind } from "@/lib/api";
import { WorkloadRow } from "./WorkloadRow";
import { LogDialog } from "./LogDialog";

function relativeAge(iso?: string): string {
    if (!iso) return "never";
    const secs = Math.max(0, (Date.now() - new Date(iso).getTime()) / 1000);
    if (secs < 60) return `${Math.round(secs)}s ago`;
    if (secs < 3600) return `${Math.round(secs / 60)}m ago`;
    return `${Math.round(secs / 3600)}h ago`;
}

/** Compose stacks first, grouped under the stack name; then loose containers;
 *  then units. Not cosmetic: a stack is one thing to an operator even when it
 *  is six containers, and a flat list turns one decision into six rows. */
function group(list: Workload[]) {
    const stacks = new Map<string, Workload[]>();
    const loose: Workload[] = [];
    const units: Workload[] = [];

    for (const w of list) {
        if (w.kind === "unit") units.push(w);
        else if (w.stack) stacks.set(w.stack, [...(stacks.get(w.stack) ?? []), w]);
        else loose.push(w);
    }

    const byName = (a: Workload, b: Workload) => a.name.localeCompare(b.name);
    return {
        stacks: [...stacks.entries()].sort((a, b) => a[0].localeCompare(b[0])).map(([name, items]) => [name, items.sort(byName)] as const),
        loose: loose.sort(byName),
        units: units.sort(byName),
    };
}

export function WorkloadList({ serverId, canControl }: { serverId: string; canControl: boolean }) {
    const qc = useQueryClient();
    const [error, setError] = useState<string | null>(null);
    const [logTarget, setLogTarget] = useState<Workload | null>(null);

    const snapshot = useQuery({
        queryKey: ["workloads", serverId],
        queryFn: () => workloads.forServer(serverId),
    });

    const refresh = useMutation({
        mutationFn: () => workloads.refresh(serverId),
        // The refresh returns no data — the agent reports through the normal
        // path, so the only correct move is to refetch the stored document.
        onSuccess: () => {
            setError(null);
            setTimeout(() => qc.invalidateQueries({ queryKey: ["workloads", serverId] }), 1500);
        },
        onError: (e: Error) => setError(e.message),
    });

    const control = useMutation({
        mutationFn: ({ w, action }: { w: Workload; action: WorkloadAction }) => workloads.control(serverId, w.kind as WorkloadKind, w.id, action),
        onSuccess: () => {
            setError(null);
            qc.invalidateQueries({ queryKey: ["workloads", serverId] });
        },
        onError: (e: Error) => setError(e.message),
    });

    // Opening the panel asks for a fresh list: this page carries a Restart
    // button, and a stale row is a wrong action aimed at something already dead.
    useEffect(() => {
        refresh.mutate();
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [serverId]);

    const data = snapshot.data;
    const grouped = useMemo(() => group(data?.workloads ?? []), [data]);

    const row = (w: Workload) => (
        <WorkloadRow
            key={`${w.kind}:${w.id}`}
            workload={w}
            canControl={canControl}
            busy={control.isPending}
            onAction={(action) => control.mutate({ w, action })}
            onLogs={() => setLogTarget(w)}
        />
    );

    return (
        <Card padding={false}>
            <div className="flex flex-wrap items-center justify-between gap-3 border-b border-border px-6 py-4">
                <div>
                    <h2 className="text-lg font-semibold text-text-primary">Workloads</h2>
                    <p className="mt-0.5 text-xs text-text-secondary">Collected {relativeAge(data?.collected_at)}</p>
                </div>
                <Button variant="ghost" size="sm" loading={refresh.isPending} onClick={() => refresh.mutate()}>
                    Refresh
                </Button>
            </div>

            <div className="px-6 py-4">
                {error && <p className="mb-3 text-sm text-danger">{error}</p>}

                {snapshot.isLoading ? (
                    <p className="text-sm text-text-secondary">Loading…</p>
                ) : !data ? (
                    <p className="text-sm text-text-secondary">Nothing reported yet. Agents report every 60 seconds, on Linux only.</p>
                ) : (
                    <div className="space-y-2 text-sm">
                        {/* Docker absent is the common case on a fleet built
                            around SSH keys, and is not a fault. Installed but
                            not responding is a different problem, so it reads
                            differently. */}
                        {data.docker_error ? (
                            <p className="text-warning">Docker is installed but not responding: {data.docker_error}</p>
                        ) : !data.docker_ok ? (
                            <p className="text-text-secondary">Docker is not in use on this server.</p>
                        ) : null}

                        {data.systemd_error ? (
                            <p className="text-warning">systemd could not be read: {data.systemd_error}</p>
                        ) : !data.systemd_ok ? (
                            <p className="text-text-secondary">systemd is not in use on this server.</p>
                        ) : null}
                    </div>
                )}
            </div>

            {grouped.stacks.map(([stack, items]) => (
                <div key={stack}>
                    <div className="border-y border-border bg-surface-2 px-6 py-2 text-xs font-medium uppercase tracking-[0.08em] text-text-secondary">
                        stack · {stack}
                    </div>
                    {items.map(row)}
                </div>
            ))}

            {grouped.loose.length > 0 && (
                <div>
                    <div className="border-y border-border bg-surface-2 px-6 py-2 text-xs font-medium uppercase tracking-[0.08em] text-text-secondary">containers</div>
                    {grouped.loose.map(row)}
                </div>
            )}

            {grouped.units.length > 0 && (
                <div>
                    <div className="border-y border-border bg-surface-2 px-6 py-2 text-xs font-medium uppercase tracking-[0.08em] text-text-secondary">services</div>
                    {grouped.units.map(row)}
                </div>
            )}

            {logTarget && (
                <LogDialog
                    serverId={serverId}
                    kind={logTarget.kind as WorkloadKind}
                    id={logTarget.id}
                    name={logTarget.name}
                    onClose={() => setLogTarget(null)}
                />
            )}
        </Card>
    );
}
