// Copyright (c) 2026 defconxt. All rights reserved.
// Licensed under AGPL-3.0 - see LICENSE file for details.
// NERF is a trademark of defconxt.

/**
 * phase-router.js: Per-phase model routing for NERF.
 *
 * Routes different work phases to different LLM models based on config:
 *   - research: deep reasoning models (e.g. deepseek-r1)
 *   - planning: high-quality models (e.g. claude-opus)
 *   - execution: balanced models (e.g. claude-sonnet)
 *   - completion: fast models for summaries
 *
 * Falls back to the default backend when phase routing is not configured.
 *
 * @module execution-engine/phase-router
 */

import { loadConfig } from '../config.js';

const debug = process.env.NERF_DEBUG === '1'
  ? (/** @type {string} */ msg) => process.stderr.write(`[phase-router] ${msg}\n`)
  : () => {};

/**
 * @typedef {'research' | 'planning' | 'execution' | 'completion'} Phase
 */

/**
 * Resolve the model configuration for a given phase.
 *
 * Config format:
 *   models:
 *     research: "openrouter/deepseek/deepseek-r1"
 *     planning:
 *       model: "claude-opus-4-6"
 *       fallbacks:
 *         - "openrouter/anthropic/claude-3.5-sonnet"
 *     execution: "claude-sonnet-4-6"
 *     completion: "claude-sonnet-4-6"
 *
 * @param {Phase} phase
 * @param {Object} [configOverride] - Config object (uses loadConfig() if not provided)
 * @returns {{ model: string, provider: string | null, fallbacks: string[] }}
 */
export function resolvePhaseModel(phase, configOverride) {
  const config = configOverride || loadConfig();
  const models = config.models || {};
  const entry = models[phase];

  if (!entry) {
    // No phase-specific config: use default backend
    const backend = config.llm_backend || 'claude';
    const backendConfig = config[backend] || {};
    const model = backendConfig.model || 'claude-sonnet-4-6';
    debug(`Phase '${phase}': no config, using default ${backend}/${model}`);
    return { model, provider: backend, fallbacks: [] };
  }

  if (typeof entry === 'string') {
    // Simple string: "provider/model" or just "model"
    const parsed = parseModelSpec(entry);
    debug(`Phase '${phase}': ${parsed.provider || 'default'}/${parsed.model}`);
    return { ...parsed, fallbacks: [] };
  }

  if (typeof entry === 'object' && entry.model) {
    // Object with model + optional fallbacks
    const parsed = parseModelSpec(entry.model);
    const fallbacks = (entry.fallbacks || []).map(f => typeof f === 'string' ? f : f.model || f);
    debug(`Phase '${phase}': ${parsed.provider || 'default'}/${parsed.model} (${fallbacks.length} fallbacks)`);
    return { ...parsed, fallbacks };
  }

  // Unknown format
  debug(`Phase '${phase}': unrecognized config format, using defaults`);
  return { model: 'claude-sonnet-4-6', provider: null, fallbacks: [] };
}

/**
 * Parse a model spec string like "openrouter/deepseek/deepseek-r1" or "claude-sonnet-4-6".
 *
 * @param {string} spec
 * @returns {{ model: string, provider: string | null }}
 */
export function parseModelSpec(spec) {
  // Format: "provider/org/model" or "provider/model" or "model"
  const parts = spec.split('/');

  if (parts.length >= 3) {
    // "openrouter/deepseek/deepseek-r1" -> provider=openrouter, model=deepseek/deepseek-r1
    return { provider: parts[0], model: parts.slice(1).join('/') };
  }

  if (parts.length === 2) {
    // Could be "provider/model" or "org/model"
    const knownProviders = new Set([
      'anthropic', 'openai', 'openrouter', 'ollama', 'google',
      'groq', 'cerebras', 'mistral', 'xai', 'bedrock', 'azure',
    ]);
    if (knownProviders.has(parts[0])) {
      return { provider: parts[0], model: parts[1] };
    }
    // Not a known provider, treat whole thing as model name
    return { provider: null, model: spec };
  }

  return { provider: null, model: spec };
}

/**
 * Determine the execution phase from engagement state and task context.
 *
 * @param {string} engagementPhase - From STATE.md (ready|research|planning|executing|reporting)
 * @param {string} [taskType] - Optional hint from task metadata
 * @returns {Phase}
 */
export function inferPhase(engagementPhase, taskType) {
  if (taskType === 'research' || engagementPhase === 'research') return 'research';
  if (taskType === 'planning' || engagementPhase === 'planning') return 'planning';
  if (taskType === 'reporting' || taskType === 'summary') return 'completion';
  return 'execution';
}
