// app/api/mines/projects/[id]/diligence/route.js
//
// POST — kick off the full agent-driven diligence pipeline for a project and
//        return immediately (202). Progress streams over /api/events/stream as
//        `mines_diligence` events; artifacts land in the project's dashboard
//        space. [id] is the mines_projects.id.
// GET  — whether a run is currently in flight for this project.

import { NextResponse } from 'next/server';
import { requireFreshMembership, requireSession } from '@/lib/auth.js';
import { requireRole } from '@/lib/authz.js';
import { assertMinesProjectForOrg } from '@/lib/mines/project-auth.js';
import { assertEngineAvailable } from '@/lib/agent-engines.js';
import { runDiligencePipeline, runSingleReport, resolveMinesEngine } from '@/lib/mines/diligence.js';
import { newId } from '@/lib/db.js';

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

// Process-local guard: one diligence run per project at a time. Keyed by mines
// project id. Survives across requests in the persistent local server.
function runs() {
  if (!globalThis.__minesDiligenceRuns) globalThis.__minesDiligenceRuns = new Map();
  return globalThis.__minesDiligenceRuns;
}

export async function GET(request, { params }) {
  const { id } = await params;
  let session;
  try {
    session = await requireSession(request);
    await requireFreshMembership(session, session.org_id);
    requireRole(session, 'viewer', session.org_id);
  } catch (err) {
    if (err && typeof err === 'object' && err.status) {
      return NextResponse.json({ error: err.error || 'unauthorized' }, { status: err.status });
    }
    throw err;
  }
  const active = runs().get(id) || null;
  return NextResponse.json({ running: Boolean(active), run_id: active?.run_id || null });
}

export async function POST(request, { params }) {
  const { id } = await params;

  let session;
  try {
    session = await requireSession(request);
    await requireFreshMembership(session, session.org_id);
    requireRole(session, 'admin', session.org_id);
  } catch (err) {
    if (err && typeof err === 'object' && err.status) {
      return NextResponse.json({ error: err.error || 'unauthorized' }, { status: err.status });
    }
    throw err;
  }

  const projectAccess = assertMinesProjectForOrg(id, session.org_id);
  if (!projectAccess.ok) {
    return NextResponse.json({ error: projectAccess.error }, { status: 404 });
  }

  // Optional body: { engine?, report_kind? }. `engine` is a cost/scale tier
  // (claude-code = personal CLI subscription, anthropic = production API key),
  // NOT a capability gate. `report_kind` runs a single report instead of the
  // full pipeline.
  let body = {};
  try { body = await request.json(); } catch { /* no/invalid body → defaults */ }
  const report_kind = typeof body?.report_kind === 'string' ? body.report_kind : null;

  // Per-engine availability gate replaces the old hard Anthropic-API-key block:
  // require an API key only when the API engine is chosen; require the CLI to be
  // reachable when the CLI engine is chosen. A CLI-subscription user with no API
  // key can now run mines work.
  const engine = resolveMinesEngine({ engine: body?.engine });
  try {
    await assertEngineAvailable(engine);
  } catch (err) {
    if (err && err.code === 'engine_unavailable') {
      return NextResponse.json({ error: 'engine_unavailable', engine, reason: err.message }, { status: 400 });
    }
    throw err;
  }

  // Single-report path: synchronous, returns the artifact id. Not subject to the
  // per-project run guard (it is a one-shot, not the long pipeline).
  if (report_kind) {
    const result = await runSingleReport({
      projectId: id,
      report_kind,
      engine,
      user_id: session.user_id,
      org_id: session.org_id,
    });
    const status = result.status === 'ok' ? 200 : 400;
    return NextResponse.json(result, { status });
  }

  if (runs().has(id)) {
    const active = runs().get(id);
    return NextResponse.json({ status: 'already_running', run_id: active.run_id }, { status: 409 });
  }

  const run_id = newId('mdil');
  // Fire-and-forget: the local server process is long-lived, so the detached
  // promise runs to completion while the browser watches the live-event stream.
  const promise = runDiligencePipeline({
    projectId: id,
    user_id: session.user_id,
    org_id: session.org_id,
    engine,
    run_id,
  })
    .catch((err) => { console.error('[mines/diligence] pipeline error:', err); })
    .finally(() => { runs().delete(id); });

  runs().set(id, { run_id, startedAt: Date.now(), promise });

  return NextResponse.json({ status: 'started', run_id, project_id: id, engine }, { status: 202 });
}
