"""Base class for benchmark strategies."""

from __future__ import annotations

from abc import ABC, abstractmethod

from cohort.benchmark.code_runner import extract_code
from cohort.benchmark.config import CodingTask, StrategyResult, TokenUsage, TurnLog
from cohort.benchmark.llm_backend import LLMBackend


class Strategy(ABC):
    """Abstract base for orchestration strategies."""

    NAME: str = "base"

    def __init__(self, llm: LLMBackend, task: CodingTask) -> None:
        self.llm = llm
        self.task = task
        self.turns: list[TurnLog] = []
        self.token_usage = TokenUsage()
        self._turn_counter = 0

    def _call_llm(
        self,
        agent_id: str,
        system: str,
        user: str,
        temperature: float = 0.2,
    ) -> str:
        """Make an LLM call, record the turn, return the text."""
        resp = self.llm.generate(system=system, user=user, temperature=temperature)
        self._turn_counter += 1
        self.token_usage.record(resp.tokens_in, resp.tokens_out)
        self.turns.append(TurnLog(
            turn_number=self._turn_counter,
            agent_id=agent_id,
            content=resp.text,
            tokens_in=resp.tokens_in,
            tokens_out=resp.tokens_out,
        ))
        return resp.text

    def _extract_latest_code(self) -> str:
        """Extract code from the most recent turn that contains code."""
        for turn in reversed(self.turns):
            code = extract_code(turn.content)
            if code:
                return code
        return ""

    @abstractmethod
    def run(self) -> StrategyResult:
        """Execute the strategy. Returns the result with final code."""
        ...

    def _build_result(
        self, final_code: str, elapsed: float,
        failure_modes: list[str] | None = None,
    ) -> StrategyResult:
        return StrategyResult(
            strategy_name=self.NAME,
            final_code=final_code,
            turns=list(self.turns),
            token_usage=self.token_usage,
            elapsed_seconds=elapsed,
            failure_modes=failure_modes or [],
        )
