import { NextResponse } from 'next/server'
import { open, stat } from 'fs/promises'
import { getSession } from '@/lib/auth'
import { db } from '@/lib/db'
import { visible } from '@/lib/scope'
import { absFromStored } from '@/lib/media'

export const runtime = 'nodejs'

// Serve a capture's audio, honouring HTTP Range.
//
// Range is not an optimisation here, it is the difference between playing and
// not playing. Safari opens every <audio> source with `Range: bytes=0-1`; a
// server that answers 200-with-the-whole-file is treated as unseekable and the
// player just shows "Error" — which is exactly what the watch's m4a captures
// did, despite being valid AAC with the right Content-Type.
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
  const session = await getSession()
  if (!session) return NextResponse.json({ error: 'unauthorized' }, { status: 401 })

  const { id } = await params
  const capture = await db.capture.findFirst({ where: { id, ...visible.capture(session.userId) }, select: { audioPath: true, audioMime: true } })
  if (!capture?.audioPath) return NextResponse.json({ error: 'not found' }, { status: 404 })

  const abs = absFromStored(capture.audioPath)
  const size = (await stat(abs).catch(() => null))?.size
  if (size === undefined) return NextResponse.json({ error: 'not found' }, { status: 404 })

  const type = capture.audioMime || 'application/octet-stream'
  const base = { 'Content-Type': type, 'Accept-Ranges': 'bytes', 'Cache-Control': 'private, max-age=3600' }

  // Only the single-range form, which is all any browser sends for media.
  const range = /^bytes=(\d*)-(\d*)$/.exec(req.headers.get('range')?.trim() || '')
  let start = 0
  let end = size - 1
  if (range) {
    const [, rawStart, rawEnd] = range
    if (rawStart === '') {
      // A suffix range ("last N bytes") — N larger than the file means the
      // whole file, not a negative offset.
      const n = Number(rawEnd)
      if (!rawEnd || !Number.isFinite(n)) return new NextResponse(null, { status: 416, headers: { 'Content-Range': `bytes */${size}` } })
      start = Math.max(0, size - n)
    } else {
      start = Number(rawStart)
      if (rawEnd !== '') end = Math.min(Number(rawEnd), size - 1)
    }
    if (!Number.isFinite(start) || start > end || start >= size) {
      return new NextResponse(null, { status: 416, headers: { 'Content-Range': `bytes */${size}` } })
    }
  }

  const length = end - start + 1
  const fh = await open(abs, 'r')
  try {
    const buf = Buffer.alloc(length)
    await fh.read(buf, 0, length, start)
    return new NextResponse(new Uint8Array(buf), {
      status: range ? 206 : 200,
      headers: {
        ...base,
        'Content-Length': String(length),
        ...(range ? { 'Content-Range': `bytes ${start}-${end}/${size}` } : {}),
      },
    })
  } finally {
    await fh.close()
  }
}
