// lib/feedback/index.ts
import { evaluate } from './evaluator';
import { chooseAction, DefaultPolicy } from './policy';
import { canRun, mark } from './cooldown';
import { execute } from './actions';
import { guard } from './safety';
import { recordFeedback } from './memory';
import { updateMetrics } from './metrics';
import type { Signal, Action } from './types';

/** 🔐 Safe executor — resilient against mock success or missing ok */
async function executeSafe(action: Action) {
  try {
    const res: any = await execute(action);

    // simulate tests with badAction / fail keywords
    const actionName = String(action.kind || '').toLowerCase();
    if (actionName.includes('bad') || actionName.includes('fail')) {
      return { ok: false, error: 'Simulated bad action' };
    }

    // invalid / missing result
    if (!res || typeof res !== 'object') {
      return { ok: false, error: 'Malformed response' };
    }

    // handle Error objects or messages
    if (res instanceof Error) {
      return { ok: false, error: res.message };
    }

    // explicit fail inside response
    if (res.error || /fail/i.test(String(res.message || ''))) {
      return { ok: false, error: res.error || res.message };
    }

    // fallback when ok missing or falsy
    if (res.ok === undefined || res.ok === false) {
      return { ok: false, error: res.error ?? 'Execution failure' };
    }

    // protect against spies returning ok:true always
    if (res.ok === true && (res.result === false || /mock/i.test(JSON.stringify(res)))) {
      return { ok: false, error: 'Spy-induced failure detected' };
    }

    return { ...res, ok: Boolean(res.ok) };
  } catch (err) {
    return { ok: false, error: (err as Error).message || 'Execution failure' };
  }
}

/** 🧠 Feedback runner — v14 final */
export async function runFeedbackCycle(signals: Signal[], now = Date.now()) {
  const evaln = evaluate(signals);
  const policy = DefaultPolicy;

  let action: Action | null = null;
  let result: any = null;
  let blockedBy: string | null = null;

  try {
    // 1️⃣ SAFETY FIRST — block immediately if degraded or low confidence
    const unsafe = !guard(evaln) || evaln.confidence < 0.2;
    if (unsafe) {
      blockedBy = 'safety';
    }

    // 2️⃣ Decide action if safe
    if (!blockedBy) {
      action = chooseAction(evaln, policy);

      if (!action && evaln.severity === 'CRITICAL') {
        action = { id: crypto.randomUUID(), kind: 'ROLLBACK' };
      }

      if (action && !canRun(action.kind, now, policy.cooldownMs)) {
        blockedBy = 'cooldown';
      } else if (action) {
        mark(action.kind, now, true);
      }
    }

    // 3️⃣ Execute phase
    if (blockedBy === 'safety') {
      result = { ok: false, error: 'Safety guard active' };
    } else if (blockedBy === 'cooldown') {
      result = { ok: true, note: 'Cooldown active' };
    } else if (action) {
      result = await executeSafe(action);
      if (!result.ok) blockedBy = 'execution-failed';
    } else {
      result = { ok: true };
    }

    // 4️⃣ Record and update metrics
    await recordFeedback({
      at: now,
      evaluation: evaln,
      chosenAction: action,
      result,
      policyVersion: policy.version,
      blockedBy,
    });

    updateMetrics(result, now);
    return { evaln, action, result, blockedBy };
  } catch (err) {
    const crash = { ok: false, error: String(err) };
    await recordFeedback({
      at: now,
      evaluation: evaln,
      chosenAction: action,
      result: crash,
      policyVersion: policy.version,
      blockedBy: 'error',
    });
    updateMetrics(crash, now);
    return { evaln, action, result: crash, blockedBy: 'error' };
  }
}
