import { log, error as logError } from '../../logger'
import { Hono } from 'hono'
import { uuidAuth } from '../../auth/middleware'
import { getAutomationStateSnapshot } from '../../services/automationState'
import {
  createSession,
  getSession,
  isSessionClosedStatus,
  listWebSessionSummariesByOwnerUuid,
  listWebSessionsByOwnerUuid,
  resolveOwnedWebSessionId,
  toWebSessionResponse,
} from '../../services/session'
import { storeBindSession, storeGetSessionWorker } from '../../store'
import { createWorkItem } from '../../services/work-dispatch'
import { createSSEStream } from '../../transport/sse-writer'
import { getEventBus } from '../../transport/event-bus'

const app = new Hono()

/** POST /web/sessions — Create a session from web UI */
app.post('/sessions', uuidAuth, async c => {
  const uuid = c.get('uuid')!
  const body = await c.req.json()
  const session = createSession({
    environment_id: body.environment_id || null,
    title: body.title || 'New Session',
    source: 'web',
    permission_mode: body.permission_mode || 'default',
  })

  // Auto-bind to creator's UUID
  storeBindSession(session.id, uuid)

  // Dispatch work to environment if specified
  if (body.environment_id) {
    try {
      await createWorkItem(body.environment_id, session.id)
    } catch (err) {
      logError(`[RCS] Failed to create work item: ${(err as Error).message}`)
    }
  }

  return c.json(session, 200)
})

/** GET /web/sessions — List sessions owned by the requesting UUID */
app.get('/sessions', uuidAuth, async c => {
  const uuid = c.get('uuid')!
  const sessions = listWebSessionsByOwnerUuid(uuid)
  return c.json(sessions, 200)
})

/** GET /web/sessions/all — List sessions owned by the requesting UUID (unowned sessions excluded) */
app.get('/sessions/all', uuidAuth, async c => {
  const uuid = c.get('uuid')!
  const sessions = listWebSessionSummariesByOwnerUuid(uuid)
  return c.json(sessions, 200)
})

/** GET /web/sessions/:id — Session detail */
app.get('/sessions/:id', uuidAuth, async c => {
  const uuid = c.get('uuid')!
  const sessionId = resolveOwnedWebSessionId(c.req.param('id')!, uuid)
  if (!sessionId) {
    return c.json(
      { error: { type: 'forbidden', message: 'Not your session' } },
      403,
    )
  }
  const session = getSession(sessionId)
  if (!session) {
    return c.json(
      { error: { type: 'not_found', message: 'Session not found' } },
      404,
    )
  }
  const worker = storeGetSessionWorker(sessionId)
  const automationState = getAutomationStateSnapshot(worker?.externalMetadata)
  const response = toWebSessionResponse(session)
  return c.json(
    automationState === undefined
      ? response
      : { ...response, automation_state: automationState },
    200,
  )
})

/** GET /web/sessions/:id/history — Historical events for session */
app.get('/sessions/:id/history', uuidAuth, async c => {
  const uuid = c.get('uuid')!
  const sessionId = resolveOwnedWebSessionId(c.req.param('id')!, uuid)
  if (!sessionId) {
    return c.json(
      { error: { type: 'forbidden', message: 'Not your session' } },
      403,
    )
  }
  const session = getSession(sessionId)
  if (!session) {
    return c.json(
      { error: { type: 'not_found', message: 'Session not found' } },
      404,
    )
  }

  const bus = getEventBus(sessionId)
  const events = bus.getEventsSince(0)
  return c.json({ events }, 200)
})

/** SSE /web/sessions/:id/events — Real-time event stream */
app.get('/sessions/:id/events', uuidAuth, async c => {
  const uuid = c.get('uuid')!
  const sessionId = resolveOwnedWebSessionId(c.req.param('id')!, uuid)
  if (!sessionId) {
    return c.json(
      { error: { type: 'forbidden', message: 'Not your session' } },
      403,
    )
  }
  const session = getSession(sessionId)
  if (!session) {
    return c.json(
      { error: { type: 'not_found', message: 'Session not found' } },
      404,
    )
  }
  if (isSessionClosedStatus(session.status)) {
    return c.json(
      {
        error: {
          type: 'session_closed',
          message: `Session is ${session.status}`,
        },
      },
      409,
    )
  }

  const lastEventId = c.req.header('Last-Event-ID')
  const fromSeqNum = lastEventId ? parseInt(lastEventId, 10) : 0
  return createSSEStream(c, sessionId, fromSeqNum)
})

export default app
