/**
 * Ejecución de propuestas vía Cursor Bridge API (actuador).
 */
import crypto from "crypto";

export interface BridgeStatus {
  enabled: boolean;
  configured: boolean;
  url: string;
  project: string;
  online: boolean;
  health?: unknown;
  error?: string;
}

export interface BridgeExecuteResult {
  ok: boolean;
  error?: string;
  stream_id?: string;
  status?: string;
  job?: unknown;
  raw?: unknown;
  note?: string;
}

function bridgeConfig() {
  const url = (process.env.CURSOR_BRIDGE_URL || "").replace(/\/$/, "");
  const token =
    process.env.CURSOR_BRIDGE_TOKEN ||
    process.env.SUPERVISOR_DASHBOARD_TOKEN ||
    "";
  return {
    url,
    token,
    project: process.env.CURSOR_BRIDGE_PROJECT || "captajaus",
    enabled: process.env.CURSOR_API_ENABLED !== "false",
    timeoutSec: Math.max(90, Number(process.env.CURSOR_BRIDGE_TIMEOUT_SEC || 90)),
  };
}

export async function bridgeStatus(): Promise<BridgeStatus> {
  const cfg = bridgeConfig();
  const out: BridgeStatus = {
    enabled: cfg.enabled,
    configured: Boolean(cfg.url && cfg.token),
    url: cfg.url,
    project: cfg.project,
    online: false,
  };
  if (!cfg.url) return out;
  try {
    const r = await fetch(`${cfg.url}/health`, { signal: AbortSignal.timeout(5000) });
    out.online = r.status < 500;
    try {
      out.health = await r.json();
    } catch {
      out.health = { status_code: r.status };
    }
  } catch (exc) {
    out.error = exc instanceof Error ? exc.message : String(exc);
  }
  return out;
}

export async function executePrompt(
  prompt: string,
  opts?: { project?: string; newChat?: boolean; wait?: boolean }
): Promise<BridgeExecuteResult> {
  const cfg = bridgeConfig();
  if (!cfg.enabled) return { ok: false, error: "CURSOR_API_ENABLED=false" };
  if (!cfg.url || !cfg.token) return { ok: false, error: "Bridge URL/token no configurados" };

  const headers: Record<string, string> = {
    Authorization: `Bearer ${cfg.token}`,
    "Content-Type": "application/json",
  };
  const payload = {
    project: opts?.project || cfg.project,
    message: prompt,
    newChat: opts?.newChat !== false,
    mobileLight: true,
  };

  try {
    const start = await fetch(`${cfg.url}/api/chat`, {
      method: "POST",
      headers,
      body: JSON.stringify(payload),
      signal: AbortSignal.timeout(45000),
    });
    if (start.status === 401) return { ok: false, error: "Bridge 401 — token inválido" };
    if (!start.ok) {
      const text = await start.text().catch(() => "");
      return { ok: false, error: `Bridge ${start.status}: ${text.slice(0, 200)}` };
    }
    const data = (await start.json()) as Record<string, unknown>;
    const streamId = String(data.streamId || data.stream_id || "");
    const wait = opts?.wait !== false;

    if (!wait) return { ok: true, stream_id: streamId || undefined, raw: data };
    if (!streamId) return { ok: true, raw: data, note: "sin streamId" };

    const deadline = Date.now() + cfg.timeoutSec * 1000;
    let last: Record<string, unknown> = {};
    while (Date.now() < deadline) {
      const jobRes = await fetch(`${cfg.url}/api/chat/jobs/${streamId}`, {
        headers,
        signal: AbortSignal.timeout(10000),
      });
      if (jobRes.status >= 400) {
        await sleep(2000);
        continue;
      }
      last = (await jobRes.json()) as Record<string, unknown>;
      const status = String(last.status || last.state || "").toLowerCase();
      if (["done", "completed", "success", "finished", "ok"].includes(status)) {
        return { ok: true, stream_id: streamId, status, job: last };
      }
      if (["error", "failed"].includes(status)) {
        return { ok: false, stream_id: streamId, status, job: last };
      }
      await sleep(2000);
    }
    return {
      ok: true,
      stream_id: streamId,
      status: "timeout_running",
      job: last,
      note: "Bridge sigue trabajando; revisa Cursor",
    };
  } catch (exc) {
    return { ok: false, error: exc instanceof Error ? exc.message : String(exc) };
  }
}

function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

/** Utilidad para IDs de propuesta. */
export function newProposalId(): string {
  const day = new Date().toISOString().slice(0, 10).replace(/-/g, "");
  return `cj-${day}-${crypto.randomBytes(3).toString("hex")}`;
}
