import { NextResponse } from 'next/server'
import { getSupabase } from '@/lib/supabase'
import type { AggregateStats, QueueStats } from '@/lib/types'

export const dynamic = 'force-dynamic'
export const revalidate = 0

const LANGUAGES = ['te', 'ml', 'en', 'hi', 'pa', 'ta', 'kn', 'gu', 'bn', 'or', 'mr', 'as']
const STATUSES = ['pending', 'claimed', 'done', 'failed'] as const
const ALIVE_THRESHOLD_MS = 2 * 60_000

async function getQueueStats(): Promise<QueueStats> {
  const db = getSupabase()
  const countPromises: Promise<{ status: string; lang: string; count: number }>[] = []

  for (const status of STATUSES) {
    for (const lang of LANGUAGES) {
      const p = db.from('video_queue')
        .select('*', { count: 'exact', head: true })
        .eq('status', status)
        .eq('language', lang)
        .then(({ count }) => ({ status: status as string, lang, count: count || 0 }))
      countPromises.push(Promise.resolve(p))
    }
  }

  const results = await Promise.all(countPromises)
  const stats: QueueStats = { total: 0, pending: 0, claimed: 0, done: 0, failed: 0, languages: {} }

  for (const { status, lang, count } of results) {
    stats.total += count
    ;(stats[status as keyof Omit<QueueStats, 'total' | 'languages'>] as number) += count
    if (!stats.languages[lang]) stats.languages[lang] = { total: 0, done: 0, pending: 0, claimed: 0, failed: 0 }
    stats.languages[lang].total += count
    stats.languages[lang][status as 'done' | 'pending' | 'claimed' | 'failed'] += count
  }
  return stats
}

function isAlive(w: any): boolean {
  if (!w.last_heartbeat_at) return false
  const hbBase = w.last_heartbeat_at.split('.')[0]
  const tz = w.last_heartbeat_at.includes('+') ? '+' + w.last_heartbeat_at.split('+').pop() : 'Z'
  const hbTime = new Date(hbBase + tz).getTime()
  return (Date.now() - hbTime) < ALIVE_THRESHOLD_MS
}

async function getWorkerAggregates() {
  const db = getSupabase()
  const { data: workers, error } = await db.from('workers').select('*')
  if (error || !workers) {
    return {
      total: 0, alive: 0, online: 0, offline: 0, error: 0, ghost: 0,
      totalSegmentsSent: 0, totalSegmentsCompleted: 0, totalSegmentsFailed: 0,
      totalSegments429: 0, totalCacheHits: 0, totalBatches: 0,
      totalInputTokens: 0, totalOutputTokens: 0, totalCachedTokens: 0,
      aggregateRpm: 0, aggregateTpm: 0, avgBatchLatency: 0,
    }
  }

  const alive = workers.filter(isAlive)
  const ghost = workers.filter(w => w.status === 'online' && !isAlive(w))

  return {
    total: workers.length,
    alive: alive.length,
    online: workers.filter(w => w.status === 'online').length,
    offline: workers.filter(w => w.status === 'offline').length,
    error: workers.filter(w => w.status === 'error').length,
    ghost: ghost.length,
    totalSegmentsSent: workers.reduce((a, w) => a + (w.total_segments_sent || 0), 0),
    totalSegmentsCompleted: workers.reduce((a, w) => a + (w.total_segments_completed || 0), 0),
    totalSegmentsFailed: workers.reduce((a, w) => a + (w.total_segments_failed || 0), 0),
    totalSegments429: workers.reduce((a, w) => a + (w.total_segments_429 || 0), 0),
    totalCacheHits: workers.reduce((a, w) => a + (w.total_cache_hits || 0), 0),
    totalBatches: workers.reduce((a, w) => a + (w.batches_completed || 0), 0),
    totalInputTokens: workers.reduce((a, w) => a + (w.total_input_tokens || 0), 0),
    totalOutputTokens: workers.reduce((a, w) => a + (w.total_output_tokens || 0), 0),
    totalCachedTokens: workers.reduce((a, w) => a + (w.total_cached_tokens || 0), 0),
    aggregateRpm: alive.reduce((a, w) => a + (w.active_rpm || 0), 0),
    aggregateTpm: alive.reduce((a, w) => a + (w.active_tpm || 0), 0),
    avgBatchLatency: alive.length > 0
      ? alive.reduce((a, w) => a + (w.avg_batch_latency_ms || 0), 0) / alive.length : 0,
  }
}

async function getWindowedThroughput(videosRemaining: number) {
  const db = getSupabase()
  const now = new Date()
  const cutoff60m = new Date(now.getTime() - 60 * 60_000).toISOString()
  const cutoff5m  = new Date(now.getTime() - 5  * 60_000).toISOString()
  const cutoff15m = new Date(now.getTime() - 15 * 60_000).toISOString()

  const [detail15Res, count60Res] = await Promise.all([
    db.from('video_queue').select('completed_at, segment_count').eq('status', 'done')
      .gte('completed_at', cutoff15m).order('completed_at', { ascending: false }).limit(5000),
    db.from('video_queue').select('*', { count: 'exact', head: true }).eq('status', 'done')
      .gte('completed_at', cutoff60m),
  ])

  const windows = { w5: { videos: 0, segments: 0 }, w15: { videos: 0, segments: 0 }, w60: { videos: 0, segments: 0 } }
  const cutoff5mTs = now.getTime() - 5 * 60_000

  if (detail15Res.data) {
    for (const row of detail15Res.data) {
      const tBase = row.completed_at.split('.')[0]
      const tz = row.completed_at.includes('+') ? '+' + row.completed_at.split('+').pop() : 'Z'
      const t = new Date(tBase + tz).getTime()
      const segs = row.segment_count || 0
      windows.w15.videos++; windows.w15.segments += segs
      if (t >= cutoff5mTs) { windows.w5.videos++; windows.w5.segments += segs }
    }
  }

  windows.w60.videos = count60Res.count || 0
  const avgSegs = windows.w15.videos > 0 ? windows.w15.segments / windows.w15.videos : 150
  windows.w60.segments = Math.round(windows.w60.videos * avgSegs)

  const rate5 = windows.w5.videos / 5, rate15 = windows.w15.videos / 15, rate60 = windows.w60.videos / 60
  const segRate5 = windows.w5.segments / 5, segRate15 = windows.w15.segments / 15, segRate60 = windows.w60.segments / 60

  const raw = [
    { rate: rate5, w: 0.25, has: windows.w5.videos > 0 },
    { rate: rate15, w: 0.50, has: windows.w15.videos > 0 },
    { rate: rate60, w: 0.25, has: windows.w60.videos > 0 },
  ]
  const active = raw.filter(x => x.has)
  let blendedRate = 0
  if (active.length > 0) {
    const tw = active.reduce((a, x) => a + x.w, 0)
    blendedRate = active.reduce((a, x) => a + x.rate * (x.w / tw), 0)
  }
  const segActive = [
    { rate: segRate5, w: 0.25, has: windows.w5.segments > 0 },
    { rate: segRate15, w: 0.50, has: windows.w15.segments > 0 },
    { rate: segRate60, w: 0.25, has: windows.w60.segments > 0 },
  ].filter(x => x.has)
  const segTw = segActive.reduce((a, x) => a + x.w, 0)
  const blendedSeg = segActive.length > 0 ? segActive.reduce((a, x) => a + x.rate * (x.w / segTw), 0) : 0

  return {
    windows: {
      w5:  { videos: windows.w5.videos,  segments: windows.w5.segments,  videosPerMin: rate5,  segmentsPerMin: segRate5 },
      w15: { videos: windows.w15.videos, segments: windows.w15.segments, videosPerMin: rate15, segmentsPerMin: segRate15 },
      w60: { videos: windows.w60.videos, segments: windows.w60.segments, videosPerMin: rate60, segmentsPerMin: segRate60 },
    },
    blendedVideosPerMin: blendedRate,
    blendedSegmentsPerMin: blendedSeg,
    estimatedMinutesRemaining: blendedRate > 0 ? videosRemaining / blendedRate : 0,
    estimatedHoursRemaining: blendedRate > 0 ? (videosRemaining / blendedRate) / 60 : 0,
  }
}

async function getTranscriptionAggregates() {
  const db = getSupabase()
  const { count: total } = await db.from('transcription_results').select('*', { count: 'exact', head: true })
  const { data: qd } = await db.from('transcription_results')
    .select('quality_score, lang_mismatch_flag, asr_eligible, tts_clean_eligible, tts_expressive_eligible').limit(50000)

  let avgQuality = 0, langMismatches = 0, asrEligible = 0, ttsClean = 0, ttsExpressive = 0
  if (qd && qd.length > 0) {
    const scores = qd.filter(r => r.quality_score != null).map(r => r.quality_score)
    avgQuality = scores.length > 0 ? scores.reduce((a: number, b: number) => a + b, 0) / scores.length : 0
    langMismatches = qd.filter(r => r.lang_mismatch_flag).length
    asrEligible = qd.filter(r => r.asr_eligible).length
    ttsClean = qd.filter(r => r.tts_clean_eligible).length
    ttsExpressive = qd.filter(r => r.tts_expressive_eligible).length
  }
  return { total: total || 0, avgQuality, langMismatches, asrEligible, ttsCleanEligible: ttsClean, ttsExpressiveEligible: ttsExpressive }
}

async function getFlagAggregates() {
  const db = getSupabase()
  const { data: flags } = await db.from('transcription_flags').select('flag_type')
  const byType: Record<string, number> = {}
  if (flags) for (const f of flags) byType[f.flag_type] = (byType[f.flag_type] || 0) + 1
  return { total: flags?.length || 0, byType }
}

export async function GET() {
  try {
    const [queue, workers, transcriptions, flags] = await Promise.all([
      getQueueStats(), getWorkerAggregates(), getTranscriptionAggregates(), getFlagAggregates(),
    ])
    const videosRemaining = queue.pending + queue.claimed
    const eta = await getWindowedThroughput(videosRemaining)

    const result: AggregateStats = { queue, workers, transcriptions, flags, eta }
    return NextResponse.json(result)
  } catch (err) {
    console.error('Stats API error:', err)
    return NextResponse.json({ error: 'Failed to fetch stats' }, { status: 500 })
  }
}
