import { NextResponse } from "next/server";
import { requireAdmin } from "@/lib/admin-auth";
import { sql } from "@/db";

// Storage / billing monitor. Usage is SUM(size_bytes) across memories +
// attachments per family — the SAME basis the quota system enforces
// (src/lib/quota.ts), so admin numbers match what users are charged on.
const FREE_LIMIT_BYTES = 1_073_741_824; // 1 GiB (matches FREE_STORAGE_LIMIT_BYTES)
const R2_USD_PER_GB_MONTH = 0.015;      // Cloudflare R2 storage price

export async function GET(request: Request) {
  const auth = await requireAdmin(request);
  if (!auth.success) return NextResponse.json({ error: auth.error }, { status: auth.status });

  const errors: string[] = [];
  let families: Array<Record<string, unknown>> = [];
  let totalBytes = 0;
  let totalObjects = 0;
  let byDay: { date: string; bytes: number; count: number }[] = [];

  // Per-family usage — aggregate each table to one row per family BEFORE joining
  // (no cartesian blow-up), then sum. Sorted by heaviest consumer first.
  try {
    const rows = await sql`
      WITH mem AS (
        SELECT family_id, COALESCE(SUM(size_bytes::bigint), 0)::bigint AS bytes, COUNT(*)::int AS cnt
        FROM memories GROUP BY family_id
      ),
      att AS (
        SELECT family_id, COALESCE(SUM(size_bytes::bigint), 0)::bigint AS bytes, COUNT(*)::int AS cnt
        FROM attachments GROUP BY family_id
      )
      SELECT
        f.id, f.name, f.tier,
        (COALESCE(m.bytes, 0) + COALESCE(a.bytes, 0))::bigint AS total_bytes,
        COALESCE(m.cnt, 0)::int AS memory_count,
        COALESCE(a.cnt, 0)::int AS attachment_count
      FROM families f
      LEFT JOIN mem m ON m.family_id = f.id
      LEFT JOIN att a ON a.family_id = f.id
      ORDER BY total_bytes DESC
    `;
    families = rows.map((r: Record<string, unknown>) => {
      const bytes = Number(r.total_bytes) || 0;
      const isPaid = !!r.tier && r.tier !== "free";
      return {
        id: r.id,
        name: r.name,
        tier: r.tier || "free",
        isPaid,
        bytes,
        memoryCount: Number(r.memory_count) || 0,
        attachmentCount: Number(r.attachment_count) || 0,
        objectCount: (Number(r.memory_count) || 0) + (Number(r.attachment_count) || 0),
        // fraction of the free limit (paid families have no limit)
        fraction: isPaid ? 0 : bytes / FREE_LIMIT_BYTES,
        overLimit: !isPaid && bytes > FREE_LIMIT_BYTES,
      };
    });
    totalBytes = families.reduce((s, f) => s + (f.bytes as number), 0);
    totalObjects = families.reduce((s, f) => s + (f.objectCount as number), 0);
  } catch (e) {
    errors.push(`families: ${String(e)}`);
  }

  // Daily upload volume (bytes + objects), last 30 days
  try {
    const rows = await sql`
      SELECT day::date AS date, SUM(bytes)::bigint AS bytes, SUM(cnt)::int AS count
      FROM (
        SELECT DATE(created_at) AS day, COALESCE(SUM(size_bytes::bigint), 0) AS bytes, COUNT(*) AS cnt
          FROM memories WHERE created_at > NOW() - INTERVAL '30 days' GROUP BY day
        UNION ALL
        SELECT DATE(created_at) AS day, COALESCE(SUM(size_bytes::bigint), 0) AS bytes, COUNT(*) AS cnt
          FROM attachments WHERE created_at > NOW() - INTERVAL '30 days' GROUP BY day
      ) sub
      WHERE day IS NOT NULL
      GROUP BY day ORDER BY day
    `;
    byDay = rows.map((r: Record<string, unknown>) => ({
      date: r.date instanceof Date ? r.date.toISOString().split("T")[0] : String(r.date).split("T")[0],
      bytes: Number(r.bytes) || 0,
      count: Number(r.count) || 0,
    }));
  } catch (e) {
    errors.push(`by_day: ${String(e)}`);
  }

  const paidCount = families.filter(f => f.isPaid).length;
  const overLimitCount = families.filter(f => f.overLimit).length;
  const approachingCount = families.filter(f => !f.isPaid && (f.fraction as number) >= 0.8 && !(f.overLimit as boolean)).length;
  const estMonthlyCostUsd = (totalBytes / 1e9) * R2_USD_PER_GB_MONTH;

  return NextResponse.json({
    summary: {
      totalBytes,
      totalObjects,
      familyCount: families.length,
      paidCount,
      freeCount: families.length - paidCount,
      overLimitCount,
      approachingCount,
      estMonthlyCostUsd,
      freeLimitBytes: FREE_LIMIT_BYTES,
      avgBytesPerFamily: families.length ? Math.round(totalBytes / families.length) : 0,
    },
    families,
    byDay,
    ...(errors.length ? { error: errors.join(" | ") } : {}),
  });
}
