/**
 * advisoryUtils.js — Pure logic functions for the Advisories Panel.
 *
 * No React imports, no side effects — all functions are deterministic
 * and testable in isolation.
 *
 * Advisory priority (highest first):
 *   solesurvivor (3) > defusing (2) > planting (1) > default (0)
 */

// ─── Team constants (mirrors teamEnum in utilities.jsx) ───────────────────────

const TEAM_T  = 2;
const TEAM_CT = 3;

// ─── computeAdvisoryState ─────────────────────────────────────────────────────
/**
 * Determine the current advisory state from live game data.
 *
 * Priority order (highest wins when multiple conditions are true):
 *   solesurvivor > defusing > planting > default
 *
 * Phase suppression: returns 'default' immediately during freezetime / round over.
 *
 * @param {Array}       playerArray  Full player list from WebSocket frame.
 * @param {object|null} bombData     Bomb object (state, m_is_defusing, m_blow_time, …).
 * @param {object|null} roundInfo    Round object (phase, m_bomb_planted, m_is_freeze_period, …).
 * @returns {'default'|'solesurvivor'|'planting'|'defusing'}
 */
export function computeAdvisoryState(playerArray, bombData, roundInfo) {
  // ── Phase suppression (15.1) ──────────────────────────────────────────────
  // Primary: use string phase from backend (boltobserv parity).
  // Fallback: use m_is_freeze_period boolean for backward compatibility.
  const phase = roundInfo?.phase;
  if (phase === 'freezetime' || phase === 'over') {
    return 'default';
  }
  if (phase === undefined && roundInfo?.m_is_freeze_period === true) {
    return 'default';
  }

  if (!playerArray || playerArray.length === 0) {
    return 'default';
  }

  const alivePlayers = playerArray.filter(p => !p.m_is_dead);
  const aliveT       = alivePlayers.filter(p => p.m_team === TEAM_T);
  const aliveCT      = alivePlayers.filter(p => p.m_team === TEAM_CT);

  // Priority 3 — Sole Survivor
  if (aliveT.length === 1 || aliveCT.length === 1) {
    return 'solesurvivor';
  }

  // Priority 2 — Defusing (15.3)
  // Accept bomb.state === "defusing" (boltobserv parity) OR legacy m_is_defusing flag.
  if (bombData?.state === 'defusing' || bombData?.m_is_defusing === true) {
    return 'defusing';
  }

  // Priority 1 — Planting (15.2)
  // Accept bomb.state === "planting" (boltobserv parity) OR legacy m_bomb_planted fallback.
  if (
    bombData?.state === 'planting' ||
    (roundInfo?.m_bomb_planted === true && (bombData?.m_blow_time ?? 0) > 0)
  ) {
    return 'planting';
  }

  // Priority 0 — Default (no advisory)
  return 'default';
}

// ─── resolveBombSite ──────────────────────────────────────────────────────────
/**
 * Resolve a human-readable site label from the bomb's m_bomb_site index.
 *
 * @param {object|null} bombData  Bomb object containing m_bomb_site (0 = A, 1 = B).
 * @returns {'[A]'|'[B]'|''}
 */
export function resolveBombSite(bombData) {
  if (bombData?.m_bomb_site === 0) return '[A]';
  if (bombData?.m_bomb_site === 1) return '[B]';
  return '';
}

// ─── resolveAdvisoryPlayer ────────────────────────────────────────────────────
/**
 * Resolve the name of the player most relevant to the current advisory state.
 *
 * For the 'planting' state the return value is prefixed with the bomb site label
 * when available: '[A] PlayerName', '[B] PlayerName', or just 'PlayerName'.
 *
 * Falls back to a team indicator ("T" or "CT") when no name is available.
 *
 * @param {'default'|'solesurvivor'|'planting'|'defusing'} state
 * @param {Array}       playerArray  Full player list.
 * @param {object|null} bombData     Bomb object (used for site label + defusing fallback).
 * @returns {string}  Player name (optionally prefixed with site), team indicator, or ''.
 */
export function resolveAdvisoryPlayer(state, playerArray, bombData) {
  if (!playerArray) return '';

  switch (state) {
    case 'planting': {
      // (15.4) Prefer the player who has the bomb AND is actively holding C4
      // (m_weapons.m_active === 'c4'), then fall back to any alive bomb carrier.
      const planter =
        playerArray.find(p => p.m_has_bomb && !p.m_is_dead && p.m_weapons?.m_active === 'c4') ??
        playerArray.find(p => p.m_has_bomb && !p.m_is_dead);
      const playerName = planter?.m_name || 'T';
      const siteLabel  = resolveBombSite(bombData);
      // Format: '[A] PlayerName', '[B] PlayerName', or just 'PlayerName'
      return siteLabel ? `${siteLabel} ${playerName}` : playerName;
    }

    case 'defusing': {
      // Prefer a CT explicitly flagged as defusing; fall back to any alive CT
      const defuser =
        playerArray.find(p => p.m_team === TEAM_CT && !p.m_is_dead && p.m_is_defusing) ??
        playerArray.find(p => p.m_team === TEAM_CT && !p.m_is_dead);
      return defuser?.m_name || 'CT';
    }

    case 'solesurvivor': {
      const alivePlayers = playerArray.filter(p => !p.m_is_dead);
      const aliveT       = alivePlayers.filter(p => p.m_team === TEAM_T);
      const aliveCT      = alivePlayers.filter(p => p.m_team === TEAM_CT);

      if (aliveT.length === 1)  return aliveT[0].m_name  || 'T';
      if (aliveCT.length === 1) return aliveCT[0].m_name || 'CT';
      return '';
    }

    default:
      return '';
  }
}
