import { NextRequest } from "next/server";
import { spawn, type ChildProcessWithoutNullStreams } from "child_process";
import { getAdminUser } from "@/lib/auth/admin";
import { clientIp } from "@/lib/auth/rateLimit";
import {
  logSecurityEventAsync,
  SecurityEventType,
} from "@/lib/auth/securityEvents";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

// Container names, kept in sync with `container_name:` in docker-compose.yml.
// We stream via `docker logs -f <container>` rather than `docker compose logs`
// because this route may itself run inside the `app` container (see the
// docker.sock mount there), where no docker-compose.yml is present and the
// compose "project name" can't be reliably resolved — fixed container names
// sidestep both problems.
const SERVICE_CONTAINERS: Record<string, string> = {
  app: "scanreceipts_app",
  postgres: "scanreceipts_postgres",
};

export async function GET(req: NextRequest) {
  const admin = await getAdminUser();
  if (!admin) return new Response("Forbidden", { status: 403 });

  const requested = req.nextUrl.searchParams.get("service");
  const targets: [string, string][] =
    requested && SERVICE_CONTAINERS[requested]
      ? [[requested, SERVICE_CONTAINERS[requested]]]
      : Object.entries(SERVICE_CONTAINERS);

  logSecurityEventAsync({
    type: SecurityEventType.ADMIN_ACTION,
    userId: admin.id,
    email: admin.email,
    ip: clientIp(req),
    userAgent: req.headers.get("user-agent"),
    metadata: { route: "/api/admin/logs/stream", method: "GET", service: requested ?? "all" },
  });

  const encoder = new TextEncoder();
  let streamClosed = false;

  const stream = new ReadableStream<Uint8Array>({
    start(controller) {
      const children: ChildProcessWithoutNullStreams[] = [];
      let activeCount = targets.length;

      const emit = (event: string | null, text: string) => {
        if (streamClosed) return;
        const framed = (event ? `event: ${event}\n` : "") + `data: ${text}\n\n`;
        controller.enqueue(encoder.encode(framed));
      };

      const finishOne = () => {
        activeCount -= 1;
        if (activeCount <= 0 && !streamClosed) {
          emit("fatal", "Alle Log-Streams beendet.");
          streamClosed = true;
          controller.close();
        }
      };

      for (const [label, containerName] of targets) {
        const prefix = targets.length > 1 ? `[${label}] ` : "";
        const send = (chunk: Buffer) => {
          const lines = chunk.toString("utf8").split(/\r?\n/).filter((l) => l.length > 0);
          for (const line of lines) emit(null, prefix + line);
        };

        const child = spawn("docker", ["logs", "-f", "--tail", "300", "--timestamps", containerName]);
        children.push(child);

        child.stdout.on("data", send);
        child.stderr.on("data", send);

        child.on("error", (err) => {
          emit(null, `${prefix}[fehler] docker CLI nicht erreichbar: ${err.message}`);
          finishOne();
        });

        child.on("close", (code) => {
          emit(null, `${prefix}[stream beendet, code ${code}]`);
          finishOne();
        });
      }

      req.signal.addEventListener("abort", () => {
        streamClosed = true;
        for (const child of children) child.kill();
        try {
          controller.close();
        } catch {
          // already closed
        }
      });
    },
  });

  return new Response(stream, {
    headers: {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache, no-transform",
      Connection: "keep-alive",
      "X-Accel-Buffering": "no",
    },
  });
}
