export const dynamic = 'force-dynamic';
export const revalidate = 0;

import { NextResponse } from 'next/server';
import { getOrgId, getOrgRole, getUserId } from '../../lib/org.js';
import { checkQuotaFast, getOrgPlan, incrementMeter } from '../../lib/usage.js';
import { logActivity } from '../../lib/audit.js';
import { getSql } from '../../lib/db.js';
import crypto from 'crypto';
import { isSelfHostModeEnabled } from '../../lib/selfHost.js';

function hashKey(key) {
  return crypto.createHash('sha256').update(key).digest('hex');
}

function generateApiKey() {
  const random = crypto.randomBytes(16).toString('hex');
  return `oc_live_${random}`;
}

// Store enough of the key to visually distinguish it in the dashboard.
// "oc_live_" is 8 chars and identical for every key, so we need at least
// 16 chars to show the first 8 unique hex digits after the prefix.
const KEY_PREFIX_LENGTH = 16;

// GET /api/keys - List API keys for the user's org
export async function GET(request) {
  try {
    const orgId = getOrgId(request);
    const sql = getSql();

    try {
      const keys = await sql`
        SELECT id, key_prefix, label, role, last_used_at, created_at, revoked_at
        FROM api_keys
        WHERE org_id = ${orgId}
        ORDER BY created_at DESC
      `;
      return NextResponse.json({ keys });
    } catch (dbErr) {
      // 42P01 = table not found — fresh self-host install before migration has run.
      // Self-host bypass: return empty list rather than crashing the dashboard.
      if (dbErr.code === '42P01' && isSelfHostModeEnabled()) {
        return NextResponse.json({ keys: [] });
      }
      throw dbErr;
    }
  } catch (error) {
    console.error('Keys API GET error:', error);
    return NextResponse.json({ error: 'Failed to fetch API keys' }, { status: 500 });
  }
}

// POST /api/keys - Generate a new API key (admin only)
export async function POST(request) {
  try {
    const orgId = getOrgId(request);
    if (getOrgRole(request) !== 'admin') {
      return NextResponse.json({ error: 'Admin access required to generate API keys' }, { status: 403 });
    }

    const body = await request.json();
    const { label = 'API Key' } = body;

    if (typeof label !== 'string' || label.length > 256) {
      return NextResponse.json({ error: 'Label must be a string of 256 characters or fewer' }, { status: 400 });
    }

    const sql = getSql();

    // Quota check: API keys (fast meter path)
    const plan = await getOrgPlan(orgId, sql);
    const keysQuota = await checkQuotaFast(orgId, 'api_keys', plan, sql);
    if (!keysQuota.allowed) {
      return NextResponse.json(
        { error: 'API key limit reached. Upgrade your plan.', code: 'QUOTA_EXCEEDED', usage: keysQuota.usage, limit: keysQuota.limit },
        { status: 402 }
      );
    }

    const rawKey = generateApiKey();
    const keyHash = hashKey(rawKey);
    const keyPrefix = rawKey.substring(0, KEY_PREFIX_LENGTH);
    const keyId = `key_${crypto.randomUUID()}`;

    await sql`
      INSERT INTO api_keys (id, org_id, key_hash, key_prefix, label, role)
      VALUES (${keyId}, ${orgId}, ${keyHash}, ${keyPrefix}, ${label}, 'admin')
    `;

    // Fire-and-forget meter increment
    incrementMeter(orgId, 'api_keys', sql).catch(() => {
      console.warn('[Keys] Failed to increment api_keys meter');
    });

    logActivity({
      orgId, actorId: getUserId(request) || 'unknown', action: 'key.created',
      resourceType: 'api_key', resourceId: keyId,
      details: { label, prefix: keyPrefix }, request,
    }, sql);

    return NextResponse.json({
      key: {
        id: keyId,
        raw_key: rawKey,
        prefix: keyPrefix,
        label,
        role: 'admin',
        storageWarning: 'Store this key now. It will not be shown again.'
      }
    }, { status: 201 });
  } catch (error) {
    console.error('Keys API POST error:', error);
    return NextResponse.json({ error: 'Failed to generate API key' }, { status: 500 });
  }
}

// DELETE /api/keys?id=key_xxx - Revoke an API key (admin only)
export async function DELETE(request) {
  try {
    const orgId = getOrgId(request);
    if (getOrgRole(request) !== 'admin') {
      return NextResponse.json({ error: 'Admin access required to revoke API keys' }, { status: 403 });
    }

    const { searchParams } = new URL(request.url);
    const keyId = searchParams.get('id');

    if (!keyId || !keyId.startsWith('key_')) {
      return NextResponse.json({ error: 'Valid key id is required' }, { status: 400 });
    }

    const sql = getSql();
    const existing = await sql`
      SELECT id, revoked_at FROM api_keys WHERE id = ${keyId} AND org_id = ${orgId}
    `;

    if (existing.length === 0) {
      return NextResponse.json({ error: 'API key not found' }, { status: 404 });
    }
    if (existing[0].revoked_at) {
      return NextResponse.json({ error: 'API key is already revoked' }, { status: 409 });
    }

    await sql`
      UPDATE api_keys SET revoked_at = CURRENT_TIMESTAMP WHERE id = ${keyId} AND org_id = ${orgId}
    `;

    // Fire-and-forget meter decrement
    incrementMeter(orgId, 'api_keys', sql, -1).catch(() => {
      console.warn('[Keys] Failed to decrement api_keys meter');
    });

    logActivity({
      orgId, actorId: getUserId(request) || 'unknown', action: 'key.revoked',
      resourceType: 'api_key', resourceId: keyId, request,
    }, sql);

    return NextResponse.json({ success: true, revoked: keyId });
  } catch (error) {
    console.error('Keys API DELETE error:', error);
    return NextResponse.json({ error: 'Failed to revoke API key' }, { status: 500 });
  }
}
