import { NextRequest, NextResponse } from 'next/server';
import { getCurrentUser } from '@/lib/auth';
import { assertSafeProviderUrl } from '@/lib/ai/safeUrl';

/**
 * GET /api/ai/sparkcontrol/model?baseUrl=...
 *
 * Probes SparkControl's service-discovery endpoint (`/api/endpoints`) and
 * returns the model vLLM currently has loaded, so the Settings UI can
 * auto-fill the model field (the same role the Ollama /api/tags probe plays).
 * When no baseUrl is given it walks the canonical same-box StartOS addresses
 * and, on a hit, hands back a `baseUrl` (with the `/v1` chat suffix) the UI
 * can pre-fill.
 *
 * `/api/endpoints` lives at the host root, NOT under `/v1` — so we strip a
 * trailing `/v1` off the configured chat base URL before probing.
 *
 * Authenticated + admin-only: pointing the server at an arbitrary URL is the
 * SSRF surface (same gate as the Ollama probe), and a non-admin shouldn't be
 * able to fingerprint the local network.
 *
 * Response:
 *   { ok: true,  baseUrl, model: string | null, ready: boolean | null, ms }
 *   { ok: false, baseUrl, error, ms }
 */

const PROBE_TIMEOUT_MS = 5_000;

// Canonical same-box addresses (StartOS 0.4 `.startos`, legacy 0.3 `.embassy`),
// including the `/v1` chat suffix the config field expects.
const DEFAULT_CANDIDATES = [
  'http://spark-control.startos:9999/v1',
  'http://spark-control.embassy:9999/v1',
];

export async function GET(request: NextRequest) {
  const user = await getCurrentUser();
  if (!user) return NextResponse.json({ ok: false, error: 'Unauthorized' }, { status: 401 });
  // Custom-URL surface ⇒ admin-only (same as the Ollama probe).
  if (!user.isAdmin)
    return NextResponse.json({ ok: false, error: 'Forbidden' }, { status: 403 });

  const url = new URL(request.url);
  const explicit = url.searchParams.get('baseUrl');
  const candidates = explicit ? [explicit] : DEFAULT_CANDIDATES;

  for (const candidate of candidates) {
    const result = await probe(candidate);
    if (result.ok) return NextResponse.json(result);
    // For an explicit URL, surface the failure right away.
    if (explicit) return NextResponse.json(result);
  }
  return NextResponse.json({
    ok: false,
    baseUrl: candidates[0],
    error: 'No SparkControl instance responded at the default StartOS addresses.',
    ms: 0,
  });
}

interface EndpointsResponse {
  vllm?: { ready?: boolean; model?: string | null; disabled?: boolean };
}

async function probe(baseUrl: string) {
  const t0 = Date.now();
  let url: string;
  try {
    // `/api/endpoints` lives at the host root, independent of the `/v1` chat
    // path — so probe the origin, not a string-derived prefix. (new URL also
    // throws on a malformed baseUrl, which this catch turns into ok:false.)
    url = new URL(baseUrl).origin + '/api/endpoints';
    await assertSafeProviderUrl(url);
  } catch (e) {
    return { ok: false as const, baseUrl, error: (e as Error).message, ms: Date.now() - t0 };
  }
  const ctrl = new AbortController();
  const timer = setTimeout(() => ctrl.abort(), PROBE_TIMEOUT_MS);
  try {
    const res = await fetch(url, { signal: ctrl.signal });
    clearTimeout(timer);
    if (!res.ok) {
      return {
        ok: false as const,
        baseUrl,
        error: `SparkControl returned HTTP ${res.status}`,
        ms: Date.now() - t0,
      };
    }
    const body = (await res.json()) as EndpointsResponse;
    return {
      ok: true as const,
      baseUrl,
      model: body.vllm?.model ?? null,
      ready: body.vllm?.ready ?? null,
      ms: Date.now() - t0,
    };
  } catch (e) {
    clearTimeout(timer);
    return {
      ok: false as const,
      baseUrl,
      error: ctrl.signal.aborted
        ? `Timed out after ${PROBE_TIMEOUT_MS / 1000}s`
        : (e as Error).message,
      ms: Date.now() - t0,
    };
  }
}
