/**
 * POST /api/ai-assistant/chat — SSE streaming chat route.
 *
 * Auth required. Requires Business tier + ai_assistant module enabled.
 * Creates a session on first message, streams deltas as SSE, emits done/error events.
 */
import { Hono } from 'hono'
import { z } from 'zod'
import { createDb } from '@zync/db/queries'
import { createAiChatSession, getAiChatSession } from '@zync/db/queries'
import type { AppEnv } from '../../types'
import type { SessionPayload } from '@zync/types'
import { authMiddleware } from '../../middleware/auth'
import { requireTier } from '../../middleware/guards'
import { requireModuleEnabled } from '../../middleware/require-module-enabled'
import { TenantTier } from '@zync/types'
import { streamAssistantTurn } from '@zync/ai/chat'
import { QuotaExceededError } from '@zync/ai'

const chatRouter = new Hono<AppEnv>()

chatRouter.use('*', authMiddleware)
chatRouter.use('*', requireModuleEnabled('ai_assistant'))
chatRouter.use('*', requireTier(TenantTier.BUSINESS))

const chatBody = z.object({
  sessionId: z.string().uuid().optional(),
  message: z.string().min(1).max(4000),
})

chatRouter.post('/', async (c) => {
  const session = c.get('session') as SessionPayload
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }

  const parsed = chatBody.safeParse(await c.req.json())
  if (!parsed.success) {
    return c.json({ error: 'Invalid request', details: parsed.error.flatten() }, 400)
  }

  const { sessionId: inputSessionId, message } = parsed.data
  const db = createDb(c.env)

  // Resolve or create session
  let sessionId: string
  if (inputSessionId) {
    const existing = await getAiChatSession(db, session.tid, inputSessionId)
    if (!existing || existing.userId !== session.sub) {
      return c.json({ error: 'Session not found' }, 404)
    }
    sessionId = existing.id
  } else {
    const title = message.length <= 60 ? message : message.slice(0, 57) + '...'
    const newSession = await createAiChatSession(db, session.tid, {
      userId: session.sub,
      channel: 'in_app',
      title,
    })
    sessionId = newSession.id
  }

  // Start streaming — throws QuotaExceededError before stream opens if over quota
  let streamResult: { stream: ReadableStream<string>; usagePromise: Promise<{ inputTokens: number; outputTokens: number; tokensUsed: number }> }
  try {
    streamResult = await streamAssistantTurn(c.env, {
      tenantId: session.tid,
      userId: session.sub,
      sessionId,
      message,
      tier: session.tier,
    })
  } catch (err) {
    if (err instanceof QuotaExceededError) {
      return c.json({ error: 'quota_exceeded', message: 'Monthly AI quota exhausted. Upgrade or purchase credits.' }, 402)
    }
    throw err
  }
  const { stream: deltaStream, usagePromise } = streamResult

  return new Response(
    new ReadableStream({
      async start(controller) {
        const encoder = new TextEncoder()

        // Pipe session ID as first event so client can store it
        const sessionEvent = `data: ${JSON.stringify({ type: 'session', sessionId })}\n\n`
        controller.enqueue(encoder.encode(sessionEvent))

        try {
          const reader = deltaStream.getReader()
          while (true) {
            const { done, value } = await reader.read()
            if (done) break
            const deltaEvent = `data: ${JSON.stringify({ type: 'delta', content: value })}\n\n`
            controller.enqueue(encoder.encode(deltaEvent))
          }

          const usage = await usagePromise
          const doneEvent = `data: ${JSON.stringify({
            type: 'done',
            usage: { inputTokens: usage.inputTokens, outputTokens: usage.outputTokens },
          })}\n\n`
          controller.enqueue(encoder.encode(doneEvent))
        } catch (err) {
          const msg = err instanceof Error ? err.message : 'Stream error'
          // Never echo internal details or secrets
          const safeMsg = msg.includes('key') || msg.includes('token') ? 'AI service error' : msg
          const errEvent = `data: ${JSON.stringify({ type: 'error', message: safeMsg })}\n\n`
          controller.enqueue(encoder.encode(errEvent))
        } finally {
          controller.close()
        }
      },
    }),
    {
      headers: {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        Connection: 'keep-alive',
        'X-Accel-Buffering': 'no',
      },
    },
  )
})

export { chatRouter }
