import { NextRequest, NextResponse } from 'next/server'
import { getDatabase, db_helpers } from '@/lib/db'
import { requireRole } from '@/lib/auth'
import { selfRegisterLimiter } from '@/lib/rate-limit'
import { logAuditEvent } from '@/lib/db'
import { eventBus } from '@/lib/event-bus'
import { logger } from '@/lib/logger'

const NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,62}$/
const VALID_ROLES = ['coder', 'reviewer', 'tester', 'devops', 'researcher', 'assistant', 'agent']

/**
 * POST /api/agents/register — Agent self-registration.
 *
 * Allows agents to register themselves with minimal auth (viewer role).
 * If an agent with the same name already exists, returns the existing agent
 * (idempotent upsert on status/last_seen).
 *
 * Body: { name, role?, capabilities?, framework? }
 *
 * Rate-limited to 5 registrations/min per IP to prevent spam.
 */
export async function POST(request: NextRequest) {
  const auth = requireRole(request, 'viewer')
  if ('error' in auth) return NextResponse.json({ error: auth.error }, { status: auth.status })

  const limited = selfRegisterLimiter(request)
  if (limited) return limited

  let body: any
  try {
    body = await request.json()
  } catch {
    return NextResponse.json({ error: 'Request body required' }, { status: 400 })
  }

  const name = typeof body?.name === 'string' ? body.name.trim() : ''
  const role = typeof body?.role === 'string' ? body.role.trim() : 'agent'
  const capabilities = Array.isArray(body?.capabilities) ? body.capabilities.filter((c: any) => typeof c === 'string') : []
  const framework = typeof body?.framework === 'string' ? body.framework.trim() : null

  if (!name || !NAME_RE.test(name)) {
    return NextResponse.json({
      error: 'Invalid agent name. Use 1-63 alphanumeric characters, dots, hyphens, or underscores. Must start with alphanumeric.',
    }, { status: 400 })
  }

  if (!VALID_ROLES.includes(role)) {
    return NextResponse.json({
      error: `Invalid role. Use: ${VALID_ROLES.join(', ')}`,
    }, { status: 400 })
  }

  try {
    const db = getDatabase()
    const workspaceId = auth.user.workspace_id ?? 1
    const now = Math.floor(Date.now() / 1000)

    // Check if agent already exists — idempotent: update last_seen and status
    const existing = db.prepare(
      'SELECT * FROM agents WHERE name = ? AND workspace_id = ?'
    ).get(name, workspaceId) as any | undefined

    if (existing) {
      db.prepare(
        'UPDATE agents SET status = ?, last_seen = ?, updated_at = ? WHERE id = ? AND workspace_id = ?'
      ).run('idle', now, now, existing.id, workspaceId)

      return NextResponse.json({
        agent: {
          id: existing.id,
          name: existing.name,
          role: existing.role,
          status: 'idle',
          created_at: existing.created_at,
        },
        registered: false,
        message: 'Agent already registered, status updated',
      })
    }

    // Create new agent
    const config: Record<string, any> = {}
    if (capabilities.length > 0) config.capabilities = capabilities
    if (framework) config.framework = framework

    const result = db.prepare(`
      INSERT INTO agents (name, role, status, config, created_at, updated_at, last_seen, workspace_id)
      VALUES (?, ?, 'idle', ?, ?, ?, ?, ?)
    `).run(name, role, JSON.stringify(config), now, now, now, workspaceId)

    const agentId = Number(result.lastInsertRowid)

    db_helpers.logActivity(
      'agent_created',
      'agent',
      agentId,
      name,
      `Agent self-registered: ${name} (${role})${framework ? ` via ${framework}` : ''}`,
      { name, role, framework, capabilities, self_registered: true },
      workspaceId,
    )

    logAuditEvent({
      action: 'agent_self_register',
      actor: auth.user.username,
      actor_id: auth.user.id,
      target_type: 'agent',
      target_id: agentId,
      detail: { name, role, framework, self_registered: true },
      ip_address: request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip') || 'unknown',
    })

    eventBus.broadcast('agent.created', { id: agentId, name, role, status: 'idle' })

    return NextResponse.json({
      agent: {
        id: agentId,
        name,
        role,
        status: 'idle',
        created_at: now,
      },
      registered: true,
      message: 'Agent registered successfully',
    }, { status: 201 })
  } catch (error: any) {
    if (error.message?.includes('UNIQUE constraint')) {
      // Race condition — another request registered the same name
      return NextResponse.json({ error: 'Agent name already exists' }, { status: 409 })
    }
    logger.error({ err: error }, 'POST /api/agents/register error')
    return NextResponse.json({ error: 'Registration failed' }, { status: 500 })
  }
}

export const dynamic = 'force-dynamic'
