import type { PermissionMode } from '../permissions/PermissionMode.js'
import { capitalize } from '../stringUtils.js'
import { MODEL_ALIASES, type ModelAlias } from './aliases.js'
import { getCanonicalName, getRuntimeMainLoopModel, parseUserSpecifiedModel } from './model.js'
import { isFirstPartyLikeProvider } from './providers.js'

export const AGENT_MODEL_OPTIONS = [...MODEL_ALIASES, 'inherit'] as const
export type AgentModelAlias = (typeof AGENT_MODEL_OPTIONS)[number]

export type AgentModelOption = {
  value: AgentModelAlias
  label: string
  description: string
}

/**
 * Get the default subagent model. Returns 'inherit' so subagents inherit
 * the model from the parent thread.
 */
export function getDefaultSubagentModel(): string {
  return 'inherit'
}

/**
 * Get the effective model string for an agent.
 */
export function getAgentModel(
  agentModel: string | undefined,
  parentModel: string,
  toolSpecifiedModel?: ModelAlias,
  permissionMode?: PermissionMode,
): string {
  if (process.env.SANDCODE_SUBAGENT_MODEL) {
    return parseUserSpecifiedModel(process.env.SANDCODE_SUBAGENT_MODEL)
  }

  // Non-firstParty providers (zai/openai/deepseek/mistral/gemini/openrouter/
  // openai-compat/custom) don't share the sonnet/opus/haiku family naming.
  // Resolving those aliases to legacy model IDs (e.g. claude-sonnet-4-5-...)
  // and sending them to a non-Messages-API endpoint yields "400 Unknown Model".
  // Fall back to the parent's model so the subagent uses whatever the user
  // configured via /model or --model.
  const isFirstParty = isFirstPartyLikeProvider()
  const isBareFamilyAlias = (m: string | undefined): boolean =>
    m === 'sonnet' || m === 'opus' || m === 'haiku'

  // Prioritize tool-specified model if provided
  if (toolSpecifiedModel) {
    if (!isFirstParty && isBareFamilyAlias(toolSpecifiedModel)) {
      return parentModel
    }
    if (aliasMatchesParentTier(toolSpecifiedModel, parentModel)) {
      return parentModel
    }
    return parseUserSpecifiedModel(toolSpecifiedModel)
  }

  const agentModelWithExp = agentModel ?? getDefaultSubagentModel()

  if (agentModelWithExp === 'inherit') {
    // Apply runtime model resolution for inherit to get the effective model
    // This ensures agents using 'inherit' get opusplan→Opus resolution in plan mode
    return getRuntimeMainLoopModel({
      permissionMode: permissionMode ?? 'default',
      mainLoopModel: parentModel,
      exceeds200kTokens: false,
    })
  }

  if (!isFirstParty && isBareFamilyAlias(agentModelWithExp)) {
    return parentModel
  }
  if (aliasMatchesParentTier(agentModelWithExp, parentModel)) {
    return parentModel
  }
  return parseUserSpecifiedModel(agentModelWithExp)
}

/**
 * Check if a bare family alias (opus/sonnet/haiku) matches the parent model's
 * tier. When it does, the subagent inherits the parent's exact model string
 * instead of resolving the alias to a provider default.
 *
 * Prevents surprising downgrades: a Vertex user on Opus 4.6 (via /model) who
 * spawns a subagent with `model: opus` should get Opus 4.6, not whatever
 * getDefaultOpusModel() returns for 3P.
 * See https://github.com/sandcode-sh/sandcode/issues/30815.
 *
 * Only bare family aliases match. `opus[1m]`, `best`, `opusplan` fall through
 * since they carry semantics beyond "same tier as parent".
 */
function aliasMatchesParentTier(alias: string, parentModel: string): boolean {
  const canonical = getCanonicalName(parentModel)
  switch (alias.toLowerCase()) {
    case 'opus':
      return canonical.includes('opus')
    case 'sonnet':
      return canonical.includes('sonnet')
    case 'haiku':
      return canonical.includes('haiku')
    default:
      return false
  }
}

export function getAgentModelDisplay(model: string | undefined): string {
  // When model is omitted, getDefaultSubagentModel() returns 'inherit' at runtime
  if (!model) return 'Inherit from parent (default)'
  if (model === 'inherit') return 'Inherit from parent'
  return capitalize(model)
}

/**
 * Get available model options for agents
 */
export function getAgentModelOptions(): AgentModelOption[] {
  return [
    {
      value: 'sonnet',
      label: 'Balanced',
      description: 'Balanced performance - best for most agents',
    },
    {
      value: 'opus',
      label: 'Most Capable',
      description: 'Most capable for complex reasoning tasks',
    },
    {
      value: 'haiku',
      label: 'Fast',
      description: 'Fast and efficient for simple tasks',
    },
    {
      value: 'inherit',
      label: 'Inherit from parent',
      description: 'Use the same model as the main conversation',
    },
  ]
}
