// src/rc/server.ts
import { createServer, type IncomingMessage, type ServerResponse } from 'http'
import { spawn } from 'child_process'
import { WebSocketServer, type WebSocket } from 'ws'
import { readFileSync, existsSync } from 'fs'
import { join, resolve } from 'path'
import { fileURLToPath } from 'url'
import type { RCServerConfig } from './types.js'
import { validateToken, getActiveToken } from './auth.js'
import { getSessions, registerSession } from './sessionRegistry.js'
import { addClient } from './bridge.js'

const __dirname = join(fileURLToPath(import.meta.url), '..')
let serverInstance: ReturnType<typeof createServer> | null = null
let serverPort: number = 0

export function startRCServer(config: RCServerConfig): Promise<{ url: string }> {
  return new Promise((resolve, reject) => {
    const server = createServer((req, res) => handleHTTP(req, res, config))

    const wss = new WebSocketServer({ server })

    wss.on('connection', (ws: WebSocket, req: IncomingMessage) => {
      // Validate token from query string
      const url = new URL(req.url ?? '', `http://${req.headers.host}`)
      const token = url.searchParams.get('token')
      if (!validateToken(token ?? undefined)) {
        ws.close(4001, 'Unauthorized')
        return
      }
      addClient(ws)
    })

    server.on('error', reject)

    server.listen(config.port, config.host, () => {
      serverInstance = server
      serverPort = config.port
      resolve({ url: `http://${config.host}:${config.port}` })
    })
  })
}

export function stopRCServer(): void {
  if (serverInstance) {
    serverInstance.close()
    serverInstance = null
  }
}

function handleHTTP(req: IncomingMessage, res: ServerResponse, config: RCServerConfig): void {
  const url = new URL(req.url ?? '/', `http://${req.headers.host}`)

  // API routes require auth
  if (url.pathname.startsWith('/api/')) {
    const authHeader = req.headers.authorization
    const token = authHeader?.replace('Bearer ', '')
    if (!validateToken(token)) {
      res.writeHead(401, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({ error: 'Unauthorized' }))
      return
    }
    handleAPI(req, res, url)
    return
  }

  // Serve static client
  serveClient(res, url)
}

function handleAPI(req: IncomingMessage, res: ServerResponse, url: URL): void {
  res.setHeader('Content-Type', 'application/json')

  if (url.pathname === '/api/health' && req.method === 'GET') {
    res.writeHead(200)
    res.end(JSON.stringify({ status: 'ok', version: '1.0.0' }))
    return
  }

  if (url.pathname === '/api/sessions' && req.method === 'GET') {
    res.writeHead(200)
    res.end(JSON.stringify({ sessions: getSessions() }))
    return
  }

  if (url.pathname === '/api/sessions' && req.method === 'POST') {
    handleStartSession(req, res)
    return
  }

  res.writeHead(404)
  res.end(JSON.stringify({ error: 'Not found' }))
}

function handleStartSession(req: IncomingMessage, res: ServerResponse): void {
  let body = ''
  req.on('data', (chunk) => { body += chunk })
  req.on('end', () => {
    try {
      const { cwd } = JSON.parse(body || '{}')
      const dir = resolve(cwd || process.cwd())

      if (!existsSync(dir)) {
        res.writeHead(400)
        res.end(JSON.stringify({ error: `Directory not found: ${dir}` }))
        return
      }

      const sessionId = `session-${Date.now()}`
      registerSession(sessionId, dir)

      // Spawn a new sandcode process with /rc auto-connect
      const execPath = process.argv[0]!
      const scriptArgs = process.argv[1] ? [process.argv[1]!] : []
      const child = spawn(execPath, [...scriptArgs, '--rc'], {
        cwd: dir,
        stdio: 'ignore',
        detached: true,
      })
      child.unref()

      res.writeHead(201)
      res.end(JSON.stringify({ sessionId, cwd: dir, pid: child.pid }))
    } catch {
      res.writeHead(400)
      res.end(JSON.stringify({ error: 'Invalid request body' }))
    }
  })
}

function serveClient(res: ServerResponse, url: URL): void {
  // Serve index.html for all non-API routes (SPA)
  try {
    const clientPath = join(__dirname, 'client', 'index.html')
    const html = readFileSync(clientPath, 'utf-8')
    res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
    res.end(html)
  } catch {
    res.writeHead(500)
    res.end('RC client not found')
  }
}

export function isRCServerRunning(): boolean {
  return serverInstance !== null
}

export function getRCServerPort(): number {
  return serverPort
}
