"""LiteLLM-backed LLM client with tiered endpoint support.

Three tiers, each can point to a different model/endpoint:
  fast      — quick classification tasks (Granite Nano or similar)
  analysis  — data flow reasoning (Granite Code 8B or similar)
  reasoning — compliance mapping and report generation (Llama 3.1 70B or similar)

All tiers are optional. Sanicode operates in degraded mode when no LLM
is configured — AST patterns and graph analysis still run, LLM steps are skipped.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

from sanicode.config import LLMTierConfig


class LLMNotConfiguredError(RuntimeError):
    """Raised when an LLM operation is attempted with no endpoint configured."""


@dataclass
class LLMResponse:
    """Structured response from an LLM call."""

    content: str
    model: str
    tier: str
    usage: dict[str, int]


class LLMClient:
    """Multi-tier LLM client for Sanicode analysis tasks.

    Each method corresponds to a specific analysis tier. If the endpoint
    for a tier is not configured, LLMNotConfiguredError is raised with
    instructions for setting up the endpoint via sanicode.toml.
    """

    def __init__(
        self,
        fast: LLMTierConfig | None = None,
        analysis: LLMTierConfig | None = None,
        reasoning: LLMTierConfig | None = None,
    ) -> None:
        self._tiers: dict[str, LLMTierConfig | None] = {
            "fast": fast,
            "analysis": analysis,
            "reasoning": reasoning,
        }

    @classmethod
    def from_config(cls, config: Any) -> LLMClient:
        """Construct an LLMClient from a SanicodeConfig instance.

        Args:
            config: A SanicodeConfig (or any object with a .llm attribute).
        """
        llm_cfg = config.llm
        return cls(
            fast=llm_cfg.fast if llm_cfg.fast.endpoint else None,
            analysis=llm_cfg.analysis if llm_cfg.analysis.endpoint else None,
            reasoning=llm_cfg.reasoning if llm_cfg.reasoning.endpoint else None,
        )

    def _require_tier(self, tier_name: str) -> LLMTierConfig:
        tier = self._tiers.get(tier_name)
        if tier is None:
            raise LLMNotConfiguredError(
                f"No LLM endpoint configured for the '{tier_name}' tier. "
                "Add an [llm.{tier_name}] section to your sanicode.toml with "
                "endpoint and model fields, then run 'sanicode config --show' "
                "to verify the configuration."
            )
        return tier

    def classify(self, prompt: str, **kwargs: Any) -> LLMResponse:
        """Run a fast classification task using the 'fast' tier.

        Typical use: determine whether a detected pattern is a true positive.

        Args:
            prompt: The prompt to send to the model.

        Returns:
            An LLMResponse from the fast-tier model.
        """
        tier = self._require_tier("fast")
        raise NotImplementedError(
            "LLMClient.classify() is not yet implemented. "
            f"Configured endpoint: {tier.endpoint}, model: {tier.model}"
        )

    def analyze(self, prompt: str, **kwargs: Any) -> LLMResponse:
        """Run a data flow analysis task using the 'analysis' tier.

        Typical use: assess whether data flow paths are sanitized end-to-end.

        Args:
            prompt: The prompt to send to the model.

        Returns:
            An LLMResponse from the analysis-tier model.
        """
        tier = self._require_tier("analysis")
        raise NotImplementedError(
            "LLMClient.analyze() is not yet implemented. "
            f"Configured endpoint: {tier.endpoint}, model: {tier.model}"
        )

    def reason(self, prompt: str, **kwargs: Any) -> LLMResponse:
        """Run compliance reasoning using the 'reasoning' tier.

        Typical use: generate compliance-mapped remediation recommendations.

        Args:
            prompt: The prompt to send to the model.

        Returns:
            An LLMResponse from the reasoning-tier model.
        """
        tier = self._require_tier("reasoning")
        raise NotImplementedError(
            "LLMClient.reason() is not yet implemented. "
            f"Configured endpoint: {tier.endpoint}, model: {tier.model}"
        )
