// Recap-side cache of the relay's GET /relay/capabilities response.
// The relay tells us how large an audio file it can comfortably accept
// FOR THIS SPECIFIC INSTALL given the relay's current routing config
// AND this install's tier + Gemini-cap state. The same operator config
// will route a fresh install through Gemini (chunk at 60min/30MB) and
// a cap-exhausted install through hardware (no chunking) — so the
// capabilities answer is per-install, not per-operator.
//
// Recap calls this in three places:
//   - on boot (warm the cache with safe defaults)
//   - hourly background refresh (catches operator config edits)
//   - inline before every relay-backed transcribe (so the chunking
//     decision matches the routing decision the relay will actually
//     make for this install RIGHT NOW)
//
// When the relay is unreachable, we fall back to Gemini-safe defaults
// so chunking happens defensively for long audio.

import { getRelayBaseURL } from "./relay-default.js";
import { getInstallId } from "./install-id.js";
import { getRawLicenseKey } from "./license.js";

const REFRESH_INTERVAL_MS = 60 * 60 * 1000; // hourly
const FETCH_TIMEOUT_MS = 5000;

// Safe defaults: chunk like we have been. Used until /relay/capabilities
// successfully populates the cache, OR if the relay is unreachable.
const DEFAULTS = Object.freeze({
  max_audio_mb: 30,
  max_audio_minutes: 60,
  preferred_chunk_seconds: 2700,
  // Audio-first ("walking mode") TTS availability. The relay advertises
  // whether ANY TTS backend (Kokoro on operator hardware, or ElevenLabs)
  // can serve a /relay/tts call. The frontend uses has_tts to decide
  // whether to show the "Listen" affordance; the prepare route checks it
  // before attempting synthesis. Conservative default: off until a fetch
  // confirms it.
  has_tts: false,
  tts_backend: null, // "kokoro" | "elevenlabs" | null
  tts_default_voice: null,
  reason: "default (relay unreachable or not yet fetched)",
  fetched_at: 0,
});

let cached = { ...DEFAULTS };
let refreshTimer = null;

export async function refreshRelayCapabilities() {
  const base = getRelayBaseURL();
  if (!base) return cached;
  const url = `${base.replace(/\/$/, "")}/relay/capabilities`;
  // Send install-id + license so the relay can run the per-install
  // routing decision. Both are optional from the relay's perspective —
  // missing install-id falls back to operator-wide capabilities, which
  // is still safer than nothing.
  const headers = {};
  try {
    const installId = getInstallId();
    if (installId) headers["X-Recap-Install-Id"] = installId;
  } catch {}
  try {
    const licenseKey = getRawLicenseKey();
    if (licenseKey) headers["Authorization"] = `Bearer ${licenseKey}`;
  } catch {}
  try {
    const r = await fetch(url, {
      headers,
      signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
    });
    if (!r.ok) {
      console.warn(`[relay-capabilities] ${url} returned HTTP ${r.status}`);
      return cached;
    }
    const data = await r.json();
    cached = {
      max_audio_mb:
        typeof data.max_audio_mb === "number" ? data.max_audio_mb : DEFAULTS.max_audio_mb,
      max_audio_minutes:
        typeof data.max_audio_minutes === "number"
          ? data.max_audio_minutes
          : DEFAULTS.max_audio_minutes,
      preferred_chunk_seconds:
        data.preferred_chunk_seconds === null
          ? null
          : typeof data.preferred_chunk_seconds === "number"
          ? data.preferred_chunk_seconds
          : DEFAULTS.preferred_chunk_seconds,
      has_tts: !!data.has_tts,
      tts_backend: typeof data.tts_backend === "string" ? data.tts_backend : null,
      tts_default_voice:
        typeof data.tts_default_voice === "string" ? data.tts_default_voice : null,
      reason: typeof data.reason === "string" ? data.reason : null,
      fetched_at: Date.now(),
    };
    console.log(
      `[relay-capabilities] refreshed: ${cached.max_audio_mb}MB / ${cached.max_audio_minutes}min / chunk=${cached.preferred_chunk_seconds}s (${cached.reason})`
    );
  } catch (err) {
    console.warn(`[relay-capabilities] fetch failed: ${err?.message || err}`);
  }
  return cached;
}

export function startRelayCapabilitiesRefresh() {
  // Fire-and-forget first refresh on boot; schedule hourly thereafter.
  refreshRelayCapabilities().catch(() => {});
  if (refreshTimer) clearInterval(refreshTimer);
  refreshTimer = setInterval(() => {
    refreshRelayCapabilities().catch(() => {});
  }, REFRESH_INTERVAL_MS);
}

export function getRelayCapabilities() {
  return cached;
}
