import { NextResponse } from "next/server";
import { spawn } from "node:child_process";
import { statfs } from "node:fs/promises";
import { requireAuth } from "@/lib/auth/middleware";

interface SystemDf {
  type: string;
  total: number;
  active: number;
  size: string;
  reclaimable: string;
}

function dockerSystemDf(): Promise<SystemDf[]> {
  return new Promise((resolve) => {
    const proc = spawn("docker", [
      "system",
      "df",
      "--format",
      "{{.Type}}|{{.TotalCount}}|{{.Active}}|{{.Size}}|{{.Reclaimable}}",
    ]);
    let out = "";
    proc.stdout.on("data", (d) => (out += d.toString()));
    proc.on("close", () => {
      const rows = out
        .trim()
        .split("\n")
        .filter(Boolean)
        .map((line) => {
          const [type, total, active, size, reclaimable] = line.split("|");
          return {
            type,
            total: parseInt(total) || 0,
            active: parseInt(active) || 0,
            size: size || "0B",
            reclaimable: reclaimable || "0B",
          };
        });
      resolve(rows);
    });
    proc.on("error", () => resolve([]));
  });
}

function registryCatalog(): Promise<{ repos: string[]; raw: string }> {
  return new Promise((resolve) => {
    const url = process.env.PM_REGISTRY
      ? `http://${process.env.PM_REGISTRY}/v2/_catalog`
      : "http://127.0.0.1:5000/v2/_catalog";
    const proc = spawn("curl", ["-sS", "--max-time", "5", url]);
    let out = "";
    proc.stdout.on("data", (d) => (out += d.toString()));
    proc.on("close", () => {
      try {
        const j = JSON.parse(out);
        resolve({ repos: j.repositories ?? [], raw: out });
      } catch {
        resolve({ repos: [], raw: out });
      }
    });
    proc.on("error", () => resolve({ repos: [], raw: "registry_unreachable" }));
  });
}

export async function GET(req: Request) {
  const auth = await requireAuth(req);
  if (!auth.ok) {
    return NextResponse.json({ error: "unauthorized" }, { status: auth.status });
  }

  const [df, reg, fs] = await Promise.all([
    dockerSystemDf(),
    registryCatalog(),
    statfs("/").catch(() => null),
  ]);

  const disk = fs
    ? {
        total: fs.blocks * fs.bsize,
        free: fs.bavail * fs.bsize,
        used: (fs.blocks - fs.bavail) * fs.bsize,
        usedPct: Math.round(((fs.blocks - fs.bavail) / fs.blocks) * 100),
      }
    : null;

  return NextResponse.json({
    docker: df,
    registry: { repos: reg.repos, count: reg.repos.length },
    disk,
  });
}
