import { NextResponse } from "next/server";

export const dynamic = "force-dynamic";

const SB_URL = process.env.SUPABASE_URL!;
const SB_KEY = process.env.SUPABASE_KEY!;
const VAST_KEY = process.env.VAST_KEY ?? "";

const HEARTBEAT_STALE_S = 5 * 60;

function hdrs() {
  return {
    apikey: SB_KEY,
    Authorization: `Bearer ${SB_KEY}`,
    "Content-Type": "application/json",
  };
}

async function countRows(table: string, filter = ""): Promise<number> {
  const q = filter ? `&${filter}` : "";
  const res = await fetch(`${SB_URL}/rest/v1/${table}?select=*${q}`, {
    headers: { ...hdrs(), Prefer: "count=exact", Range: "0-0" },
    cache: "no-store",
  });
  const range = res.headers.get("content-range");
  if (!range) return 0;
  const m = range.match(/\/(\d+)$/);
  return m ? parseInt(m[1]) : 0;
}

async function query(
  table: string,
  select: string,
  filter = ""
): Promise<any[]> {
  const q = filter ? `&${filter}` : "";
  const res = await fetch(`${SB_URL}/rest/v1/${table}?select=${select}${q}`, {
    headers: { ...hdrs(), Range: "0-9999" },
    cache: "no-store",
  });
  if (!res.ok) return [];
  return res.json();
}

async function fetchVastInstances(): Promise<
  Array<{ id: number; gpu_name: string; dph_total: number; actual_status: string }>
> {
  if (!VAST_KEY) return [];
  try {
    const res = await fetch("https://console.vast.ai/api/v0/instances/", {
      headers: { Authorization: `Bearer ${VAST_KEY}` },
      cache: "no-store",
    });
    if (!res.ok) return [];
    const data = await res.json();
    return (data.instances ?? []).filter(
      (i: any) => i.actual_status === "running"
    );
  } catch {
    return [];
  }
}

export async function GET() {
  try {
    const statuses = [
      "PENDING", "CLAIMED", "DOWNLOADING", "PROCESSING",
      "ENCODED", "PACKED", "DONE", "FAILED", "TIMEOUT",
    ];

    const cutoff = new Date(Date.now() - HEARTBEAT_STALE_S * 1000).toISOString();

    const [counts, workers, shardRows, shardCount, vastInstances] =
      await Promise.all([
        Promise.all(
          statuses.map((s) => countRows("encoding_videos", `status=eq.${s}`))
        ),
        query(
          "worker_encoders",
          "worker_id,gpu_name,status,videos_per_hour,avg_encode_rtf,total_videos_done,total_audio_processed_s,total_shards_produced,uptime_s,current_stage,last_heartbeat",
          `status=in.(ALIVE,LOADING_MODELS)&last_heartbeat=gte.${cutoff}`
        ),
        query("encoding_shards", "total_audio_s,size_bytes"),
        countRows("encoding_shards"),
        fetchVastInstances(),
      ]);

    const vc: Record<string, number> = {};
    statuses.forEach((s, i) => {
      vc[s] = counts[i];
    });

    const alive = workers.filter((w) => w.status === "ALIVE");
    const loadingCount = workers.filter(
      (w) => w.status === "LOADING_MODELS"
    ).length;

    const pending = vc.PENDING;
    const active =
      vc.CLAIMED + vc.DOWNLOADING + vc.PROCESSING + vc.ENCODED + vc.PACKED;
    const done = vc.DONE;
    const failed = vc.FAILED;
    const total = Object.values(vc).reduce((a, b) => a + b, 0);

    const fleetVph = alive.reduce((s, w) => s + (w.videos_per_hour ?? 0), 0);
    const totalAudioH =
      alive.reduce((s, w) => s + (w.total_audio_processed_s ?? 0), 0) / 3600;

    const shardAudioH =
      shardRows.reduce((s, r) => s + (r.total_audio_s ?? 0), 0) / 3600;
    const shardSizeGB =
      shardRows.reduce((s, r) => s + (r.size_bytes ?? 0), 0) /
      (1024 * 1024 * 1024);

    const etaH = fleetVph > 0 ? (pending + active) / fleetVph : null;

    const costPerHr = vastInstances.reduce(
      (s, i) => s + (i.dph_total ?? 0), 0
    );

    return NextResponse.json({
      videos: { pending, active, done, failed, total },
      workers: {
        alive: alive.length,
        loading: loadingCount,
        fleet_vph: Math.round(fleetVph * 10) / 10,
        total_audio_h: Math.round(totalAudioH * 10) / 10,
        list: alive.map((w) => ({
          id: w.worker_id,
          gpu: w.gpu_name,
          vph: w.videos_per_hour,
          rtf: w.avg_encode_rtf,
          done: w.total_videos_done,
          stage: w.current_stage,
          uptime_h: Math.round(((w.uptime_s ?? 0) / 3600) * 10) / 10,
        })),
      },
      instances: {
        count: vastInstances.length,
        cost_hr: Math.round(costPerHr * 100) / 100,
      },
      shards: {
        count: shardCount,
        audio_h: Math.round(shardAudioH * 10) / 10,
        size_gb: Math.round(shardSizeGB * 100) / 100,
      },
      eta_h: etaH !== null ? Math.round(etaH * 10) / 10 : null,
      ts: new Date().toISOString(),
    });
  } catch (err: any) {
    return NextResponse.json(
      { error: err.message || "Failed to fetch stats" },
      { status: 500 }
    );
  }
}
