import { NextResponse } from 'next/server'
import { db } from '@/lib/db'
import { getAdminSession } from '@/lib/auth'

export const runtime = 'nodejs'
export const dynamic = 'force-dynamic'

// GET /api/monitor/history?host=&name=&hours= — one check's readings over time.
//
// Session auth, not agent auth: this is read by /health in the browser, unlike
// /api/hosts-health which the VPS watchdog polls.
//
// Separate from /api/monitor on purpose. That endpoint is polled for every host
// and check on every page load; history is only wanted for the one row someone
// has actually opened, and folding it in would make the common case pay for the
// rare one.

const MAX_HOURS = 30 * 24
// About one point per 2-3px of a drawer-width chart. 7 days of 5-minute reports
// is 2,016 readings; drawing them all costs payload and paints a fuzzy band
// rather than a line, because the marks land closer together than they can be
// told apart.
const BUCKETS = 120

export async function GET(req: Request) {
  const session = await getAdminSession()
  if (!session) return NextResponse.json({ error: 'unauthorized' }, { status: 401 })

  const url = new URL(req.url)
  const host = url.searchParams.get('host') || ''
  const name = url.searchParams.get('name') || ''
  if (!host || !name) {
    return NextResponse.json({ error: 'host and name are required' }, { status: 400 })
  }

  const asked = Number(url.searchParams.get('hours') || 168)
  const hours = Number.isFinite(asked) ? Math.min(Math.max(asked, 1), MAX_HOURS) : 168

  const since = new Date(Date.now() - hours * 3600_000)
  const rows = await db.hostCheckSample.findMany({
    where: { host, name, at: { gte: since } },
    select: { value: true, status: true, at: true },
    orderBy: { at: 'asc' },
  })

  // The unit lives on the snapshot row, not on every sample — see the schema note.
  const check = await db.hostCheck.findUnique({
    where: { host_name: { host, name } },
    select: { unit: true, label: true },
  })

  // Bucket by time rather than by row count, so a gap in reporting stays a gap
  // instead of being closed up by neighbouring points sliding across it. A host
  // that was down for six hours should look down, not interpolated.
  const from = since.getTime()
  const span = Date.now() - from
  const width = span / BUCKETS
  const bins = new Map<number, { sum: number; n: number; min: number; max: number; worst: string }>()
  const RANK: Record<string, number> = { OK: 0, WARN: 1, CRIT: 2 }

  for (const r of rows) {
    const i = Math.min(BUCKETS - 1, Math.floor((r.at.getTime() - from) / width))
    const b = bins.get(i)
    if (!b) {
      bins.set(i, { sum: r.value, n: 1, min: r.value, max: r.value, worst: r.status })
    } else {
      b.sum += r.value; b.n++
      if (r.value < b.min) b.min = r.value
      if (r.value > b.max) b.max = r.value
      // Worst status in the bucket, never the average: a bucket that contains a
      // CRIT is a bucket where something was wrong, whatever the other readings said.
      if (RANK[r.status] > RANK[b.worst]) b.worst = r.status
    }
  }

  const points = [...bins.entries()]
    .sort((a, b) => a[0] - b[0])
    .map(([i, b]) => ({
      t: Math.round(from + (i + 0.5) * width),
      v: Math.round((b.sum / b.n) * 100) / 100,
      lo: Math.round(b.min * 100) / 100,
      hi: Math.round(b.max * 100) / 100,
      s: b.worst,
    }))

  return NextResponse.json({
    host,
    name,
    label: check?.label ?? name,
    unit: check?.unit ?? null,
    hours,
    samples: rows.length,
    points,
  })
}
