/**
 * /api/auth/config — runtime auth configuration surface.
 *
 *   GET  (public)  → { authMode, supabaseConfigured, supabaseUrl, supabaseAnonKey }
 *                    Used by middleware (Edge cannot read SQLite) and the login
 *                    form. Never returns the service-role key.
 *   POST           → { action: 'test' | 'save', mode?, url?, anonKey?, serviceKey? }
 *                    - action:'test'  → validate URL + anon key, write nothing.
 *                    - action:'save'  → persist config. Switching TO supabase
 *                      requires a passing connection test (anti-lockout).
 *
 * Authorization for save:
 *   - mode:'local' from a loopback host is ALWAYS allowed — the recovery hatch.
 *   - otherwise allowed when current mode is local (app is already open) or the
 *     caller has an owner/admin session.
 */

import {
  getAuthMode,
  getSupabaseAuthConfig,
  setAuthConfig,
  testSupabaseConnection,
  verifyRecoveryToken,
} from '@/lib/auth-config.js';
import { requireSession } from '@/lib/auth.js';

export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';

export async function GET() {
  const authMode = getAuthMode();
  const { url, anonKey } = getSupabaseAuthConfig();
  return Response.json({
    authMode,
    supabaseConfigured: Boolean(url && anonKey),
    supabaseUrl: url || null,
    supabaseAnonKey: anonKey || null,
  });
}

export async function POST(req) {
  const body = await req.json().catch(() => ({}));
  const action = body.action || 'save';
  const mode = body.mode ? String(body.mode).toLowerCase() : null;

  const currentMode = getAuthMode();

  // ── Test only: validate, write nothing ────────────────────────────────────
  // Gated like a write: in supabase mode it triggers an operator-supplied
  // outbound fetch, so require an owner/admin session (the URL is additionally
  // SSRF-guarded in testSupabaseConnection). In local mode the app is already
  // open to the single owner.
  if (action === 'test') {
    if (currentMode !== 'local') {
      let session = null;
      try { session = await requireSession(req); } catch { session = null; }
      if (!session || !['owner', 'admin'].includes(session.role)) {
        return Response.json({ ok: false, error: 'forbidden' }, { status: 403 });
      }
    }
    const eff = getSupabaseAuthConfig();
    const result = await testSupabaseConnection({
      url: body.url || eff.url,
      anonKey: body.anonKey || eff.anonKey,
    });
    return Response.json({ ok: result.ok, test: result });
  }

  // ── Save ──────────────────────────────────────────────────────────────────

  // Recovery hatch: dropping to local mode without a session requires the
  // filesystem recovery token (data/.auth-recovery-token, 0600). The Host
  // header is NOT trusted — it is client-spoofable.
  const recoveryToken = body.recoveryToken || req.headers.get('x-recovery-token') || '';
  const isRecoveryToLocal = mode === 'local' && verifyRecoveryToken(recoveryToken);

  if (!isRecoveryToLocal && currentMode !== 'local') {
    let session = null;
    try {
      session = await requireSession(req);
    } catch {
      session = null;
    }
    if (!session || !['owner', 'admin'].includes(session.role)) {
      return Response.json({ ok: false, error: 'forbidden' }, { status: 403 });
    }
  }

  // Switching to supabase must pass a connection test on the effective config.
  if (mode === 'supabase') {
    const eff = getSupabaseAuthConfig();
    const result = await testSupabaseConnection({
      url: body.url || eff.url,
      anonKey: body.anonKey || eff.anonKey,
    });
    if (!result.ok) {
      return Response.json({ ok: false, error: 'connection_failed', test: result }, { status: 422 });
    }
  }

  try {
    setAuthConfig({
      mode,
      url: body.url,
      anonKey: body.anonKey,
      serviceKey: body.serviceKey,
    });
  } catch (err) {
    return Response.json({ ok: false, error: err.message }, { status: 400 });
  }

  return Response.json({ ok: true, authMode: getAuthMode() });
}
