"""Helpers for calling external agents.

These functions forward rendered prompts to language model APIs and
optionally split the results into manageable chunks. The current
implementations are placeholders and should be replaced with real API
calls.
"""

import os
import re
import traceback
from typing import Any, Dict, Optional

import logging
from swarmauri_standard.loggers.Logger import Logger
import colorama
from colorama import Fore, Style
from dotenv import load_dotenv

# from ._config import _config

# Initialize colorama for auto-resetting colors
colorama.init(autoreset=True)

# ANSI escape sequence for underlining (colorama doesn't support underline directly)
UNDERLINE = "\033[4m"
logger = Logger(name=__name__)
logger.set_level(logging.INFO)

load_dotenv()


def call_external_agent(
    prompt: str,
    agent_env: Dict[str, str],
    cfg: Optional[Dict[str, Any]] = None,
    truncate_: bool = False,
    logger: Optional[Any] = logger,
) -> str:
    """
    Sends the rendered prompt to an external agent (e.g., a language model) and returns the generated content.

    Parameters:
      prompt (str): The prompt string to send to the external agent.
      agent_env (dict): A dictionary containing configuration for the external agent (e.g., API key, model name).
        Expected keys:
        - provider: The LLM provider to use (e.g., "openai", "anthropic", "deepinfra", "llamacpp")
        - api_key: API key for the provider
        - model_name: The specific model to use
        - max_tokens: Maximum number of tokens to generate
        - temperature: Temperature for generation (0.0-1.0)

    Returns:
      str: The content generated by the external agent.
    """
    try:
        from swarmauri.agents.QAAgent import QAAgent
        from swarmauri.messages.SystemMessage import SystemMessage

        from peagen.plugins import PluginManager
        from peagen._utils.config_loader import resolve_cfg
        from ._llm import GenericLLM
    except Exception as e:
        error_details = traceback.format_exc()  # Get full traceback details
        raise ImportError(
            f"\n\n{Fore.YELLOW}Exception: {Fore.RED}({e}){Fore.YELLOW}"
            f"\nTraceback details:\n{Fore.RED}{error_details}{Fore.YELLOW}\n"
            "\nThis often happens when an SDK package is installed in editable mode and a file has been "
            "corrupted with a bad overwrite. "
            "\nSee the issue thread here: "
            f"{Fore.BLUE}{UNDERLINE}https://github.com/swarmauri/swarmauri-sdk/issues/1300{Style.RESET_ALL}\n"
        )
    # Log the prompt (truncated if configured)
    truncated_prompt = prompt[:140] + "..." if truncate_ else prompt
    if logger:
        logger.info(f"Sending prompt to external llm: \n\t{truncated_prompt}\n")
        logger.debug(f"Agent env: {agent_env}")

    cfg = resolve_cfg() if cfg is None else cfg
    pm = PluginManager(cfg)

    llm_section = cfg.get("llm", {})
    provider = (
        agent_env.get("provider")
        or os.getenv("PROVIDER")
        or llm_section.get("default_provider")
    )
    if not provider:
        raise ValueError(
            "No LLM provider specified. Set agent_env['provider'], "
            "the PROVIDER environment variable, or llm.default_provider "
            "in .peagen.toml"
        )

    max_tokens = int(
        agent_env.get("max_tokens") or llm_section.get("default_max_tokens", 8192)
    )

    model_name = agent_env.get("model_name") or llm_section.get("default_model_name")
    temperature = agent_env.get("temperature") or llm_section.get("default_temperature")

    if agent_env.get("api_key"):
        llm_mgr = GenericLLM()
        llm = llm_mgr.get_llm(
            provider=provider,
            api_key=agent_env.get("api_key"),
            model_name=model_name,
            temperature=temperature,
            max_tokens=max_tokens,
        )
    else:
        llm = pm.get("llms", provider)
        # pm.get already applies default model and API key

    # Create QAAgent with the configured LLM
    system_context = "You are a software developer."
    agent = QAAgent(llm=llm)

    agent.conversation.system_context = SystemMessage(content=system_context)

    try:
        # Execute the prompt against the agent
        result = agent.exec(
            prompt,
            llm_kwargs={"max_tokens": max_tokens},
        )
    except KeyboardInterrupt:
        raise KeyboardInterrupt("'Interrupted...'")

    # Process and chunk the content
    content = chunk_content(result, logger)
    if logger:
        logger.debug(f"Received content length: {len(content)}")

    # Clean up
    del agent
    return content


def chunk_content(full_content: str, logger: Optional[Any] = logger) -> str:
    """
    Optionally splits the content into chunks. Returns either a single chunk
    or the full content.
    """
    # Remove any unwanted <think> blocks first
    pattern = r"<think>[\s\S]*?</think>"
    cleaned_text = re.sub(pattern, "", full_content).strip()

    try:
        from swarmauri.chunkers.MdSnippetChunker import MdSnippetChunker

        chunker = MdSnippetChunker()
        chunks = chunker.chunk_text(cleaned_text)
        if logger:
            logger.debug(f"Chunker returned {len(chunks)} chunk(s)")
        if len(chunks) > 1:
            logger.warning(
                "MdSnippetChunker found more than one snippet, took the first."
            )
            if logger:
                logger.debug("Returning first chunk of size %d", len(chunks[0][2]))
            return chunks[0][2]
        try:
            return chunks[0][2]
        except IndexError:
            logger.warning("MdSnippetChunker found no chunks, using cleaned_text.")
            if logger:
                logger.debug("Returning cleaned_text of length %d", len(cleaned_text))
            return cleaned_text
    except ImportError:
        if logger:
            logger.warning(
                "MdSnippetChunker not found. Returning full content without chunking."
            )
            logger.debug("Returning cleaned_text of length %d", len(cleaned_text))
        return cleaned_text
    except Exception as e:
        if logger:
            logger.error(f"[ERROR] Failed to chunk content: {e}")
            logger.debug("Returning cleaned_text of length %d", len(cleaned_text))
        return cleaned_text
