import { NextRequest } from 'next/server'
import { getPayload } from 'payload'
import config from '@payload-config'
import { checkSystemHealth } from '@/lib/monitoring/monitoring-service'
import { performanceTracker } from '@/lib/monitoring/performance-tracker'

const MAX_DURATION_MS = 25_000
const CYCLE_INTERVAL_MS = 5_000
const HEALTH_INTERVAL_MS = 10_000
const PERFORMANCE_INTERVAL_MS = 30_000

/**
 * Formats a named SSE event. Named events allow clients to listen selectively
 * via `eventSource.addEventListener('health', ...)` rather than processing
 * everything through the generic `onmessage` handler.
 */
function formatSSE(event: string, data: unknown): string {
  return `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`
}

/**
 * GET /api/monitoring/stream
 *
 * Server-Sent Events endpoint that pushes monitoring data to the admin
 * dashboard in real time. Emits named events: connected, health,
 * performance, alert, log, error, and reconnect.
 *
 * Requires super-admin authentication. The stream runs for up to 25 seconds
 * before asking the client to reconnect (Vercel 30-second limit).
 */
export async function GET(request: NextRequest): Promise<Response> {
  const payload = await getPayload({ config })
  const { user } = await payload.auth({ headers: request.headers })

  if (!user || !(user as { isSuperAdmin?: boolean }).isSuperAdmin) {
    return new Response('Unauthorized', { status: 401 })
  }

  const encoder = new TextEncoder()
  let lastAlertCheck = new Date()
  let lastLogCheck = new Date()
  let lastHealthSend = 0
  let lastPerfSend = 0

  const stream = new ReadableStream({
    async start(controller) {
      const startTime = Date.now()
      let cancelled = false

      // Stop polling when the client disconnects
      request.signal.addEventListener('abort', () => {
        cancelled = true
      })

      controller.enqueue(
        encoder.encode(formatSSE('connected', { timestamp: new Date().toISOString() })),
      )

      while (!cancelled && Date.now() - startTime < MAX_DURATION_MS) {
        try {
          const now = Date.now()

          if (now - lastHealthSend >= HEALTH_INTERVAL_MS) {
            const health = await checkSystemHealth()
            controller.enqueue(encoder.encode(formatSSE('health', health)))
            lastHealthSend = now
          }

          if (now - lastPerfSend >= PERFORMANCE_INTERVAL_MS) {
            const perf = performanceTracker.getMetrics('1h')
            controller.enqueue(encoder.encode(formatSSE('performance', perf)))
            lastPerfSend = now
          }

          lastAlertCheck = await emitNewAlerts(payload, controller, encoder, lastAlertCheck)
          lastLogCheck = await emitNewLogs(payload, controller, encoder, lastLogCheck)

          await new Promise((resolve) => setTimeout(resolve, CYCLE_INTERVAL_MS))
        } catch {
          // Stream closed or other error — stop the loop
          break
        }
      }

      if (!cancelled) {
        try {
          controller.enqueue(
            encoder.encode(formatSSE('reconnect', { timestamp: new Date().toISOString() })),
          )
        } catch {
          // Client already disconnected
        }
      }
      controller.close()
    },
  })

  return new Response(stream, {
    headers: {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache, no-transform',
      Connection: 'keep-alive',
      'X-Accel-Buffering': 'no',
    },
  })
}

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

/**
 * Queries recently created alerts and pushes each one as a named "alert" event.
 * Returns the updated checkpoint timestamp.
 */
async function emitNewAlerts(
  payload: Awaited<ReturnType<typeof getPayload>>,
  controller: ReadableStreamDefaultController,
  encoder: TextEncoder,
  since: Date,
): Promise<Date> {
  try {
    const result = await payload.find({
      collection: 'monitoring-alert-history',
      where: { createdAt: { greater_than: since.toISOString() } },
      limit: 10,
      sort: '-createdAt',
    })

    if (result.docs.length > 0) {
      for (const alert of result.docs) {
        controller.enqueue(encoder.encode(formatSSE('alert', alert)))
      }
      return new Date()
    }
  } catch {
    // Alert collection query failed; skip this cycle
  }

  return since
}

/**
 * Queries recent warn/error/fatal log entries and pushes each one as a
 * named "log" event. Returns the updated checkpoint timestamp.
 */
async function emitNewLogs(
  payload: Awaited<ReturnType<typeof getPayload>>,
  controller: ReadableStreamDefaultController,
  encoder: TextEncoder,
  since: Date,
): Promise<Date> {
  try {
    const result = await payload.find({
      collection: 'monitoring-logs',
      where: {
        and: [
          { createdAt: { greater_than: since.toISOString() } },
          {
            or: [
              { level: { equals: 'warn' } },
              { level: { equals: 'error' } },
              { level: { equals: 'fatal' } },
            ],
          },
        ],
      },
      limit: 20,
      sort: '-createdAt',
    })

    if (result.docs.length > 0) {
      for (const log of result.docs) {
        controller.enqueue(encoder.encode(formatSSE('log', log)))
      }
      return new Date()
    }
  } catch {
    // Log collection query failed; skip this cycle
  }

  return since
}

export const dynamic = 'force-dynamic'
export const maxDuration = 30
