'use strict';

/**
 * preflight — boot visibility (Session 65, Standard §A4).
 *
 * A healthcheck that only pings /api/health can't tell "booted degraded"
 * from "crashed and rolled back" — which is exactly how a missing garnish
 * file (content/stark-lines.json) served a 14-hour-old image silently. This
 * runs once at boot and prints ONE unambiguous line: `[preflight] OK` when
 * everything required is present, or `[preflight] DEGRADED` naming exactly
 * what is missing. It NEVER throws and NEVER blocks boot — its only job is
 * to make the container's state legible in the logs.
 *
 * Philosophy (matches the app's own doctrine): content garnish missing is
 * NOTED, not fatal (absent beats crashed). Missing critical env is named so
 * an operator sees it immediately instead of debugging a symptom later.
 */

const fs = require('fs');
const path = require('path');

// Optional content — the app runs fine without these; we just name them so a
// missing one is visible (and never silently crashes a require chain again).
const OPTIONAL_CONTENT = [
  { label: 'stark-lines.json', file: path.join(__dirname, '..', 'content', 'stark-lines.json'), note: 'media posts drop the Stark kicker' },
  { label: 'coaches.json', file: path.join(__dirname, 'config', 'coaches.json'), note: 'coach-impact feature uses no seed' },
];

// Critical env — the app boots without these but key surfaces degrade; named
// loudly so an operator fixes them before hunting a downstream symptom.
const CRITICAL_ENV = ['SUPABASE_URL', 'REDIS_URL', 'VYNDR_INTERNAL_KEY'];
// Either service-role name satisfies the Supabase write path.
const ENV_EITHER = [['SUPABASE_SERVICE_ROLE_KEY', 'SUPABASE_SERVICE_KEY']];

function runPreflight(log = console) {
  try {
    const missingContent = [];
    for (const c of OPTIONAL_CONTENT) {
      let ok = false;
      try { fs.accessSync(c.file, fs.constants.R_OK); ok = true; } catch { ok = false; }
      if (!ok) missingContent.push(`${c.label} (${c.note})`);
    }

    const missingEnv = CRITICAL_ENV.filter((k) => !process.env[k]);
    for (const group of ENV_EITHER) {
      if (!group.some((k) => process.env[k])) missingEnv.push(group.join('|'));
    }

    // Operational visibility for the pipeline knobs (not failures — states).
    const cron = process.env.SNAPSHOT_CRON === '1' ? 'armed' : 'off';
    const interval = Number(process.env.SNAPSHOT_EXPECTED_INTERVAL) > 0
      ? `${process.env.SNAPSHOT_EXPECTED_INTERVAL}s` : 'default(18000s)';

    if (missingContent.length === 0 && missingEnv.length === 0) {
      log.log(`[preflight] OK — content present, critical env present, snapshot cron ${cron}, expected-interval ${interval}`);
    } else {
      log.warn(`[preflight] DEGRADED — snapshot cron ${cron}, expected-interval ${interval}`);
      if (missingEnv.length) log.warn(`[preflight]   missing env: ${missingEnv.join(', ')}`);
      if (missingContent.length) log.warn(`[preflight]   missing content (non-fatal): ${missingContent.join(', ')}`);
    }
    return { ok: missingContent.length === 0 && missingEnv.length === 0, missingContent, missingEnv };
  } catch (e) {
    // Preflight itself must never break boot.
    try { log.warn(`[preflight] check errored (non-fatal): ${e.message}`); } catch { /* ignore */ }
    return { ok: false, error: e.message };
  }
}

module.exports = { runPreflight, __internals: { OPTIONAL_CONTENT, CRITICAL_ENV, ENV_EITHER } };
