"""
LLM Agent module for routing text queries from the BDI Core Agent to a local LLM
service and returning its responses back to the BDI Core Agent.
"""

import logging
from typing import Any

import httpx
from spade.agent import Agent
from spade.behaviour import CyclicBehaviour
from spade.message import Message

from control_backend.agents.llm.llm_instructions import LLMInstructions
from control_backend.core.config import settings


class LLMAgent(Agent):
    """
    Agent responsible for processing user text input and querying a locally
    hosted LLM for text generation. Receives messages from the BDI Core Agent
    and responds with processed LLM output.
    """

    logger = logging.getLogger("llm_agent")

    class ReceiveMessageBehaviour(CyclicBehaviour):
        """
        Cyclic behaviour to continuously listen for incoming messages from
        the BDI Core Agent and handle them.
        """

        async def run(self):
            """
            Receives SPADE messages and processes only those originating from the
            configured BDI agent.
            """
            msg = await self.receive(timeout=1)
            if not msg:
                return

            sender = msg.sender.node
            self.agent.logger.info(
                "Received message: %s from %s",
                msg.body,
                sender,
            )

            if sender == settings.agent_settings.bdi_core_agent_name:
                self.agent.logger.debug("Processing message from BDI Core Agent")
                await self._process_bdi_message(msg)
            else:
                self.agent.logger.debug("Message ignored (not from BDI Core Agent)")

        async def _process_bdi_message(self, message: Message):
            """
            Forwards user text to the LLM and replies with the generated text.
            """
            user_text = message.body
            llm_response = await self._query_llm(user_text)
            await self._reply(llm_response)

        async def _reply(self, msg: str):
            """
            Sends a response message back to the BDI Core Agent.
            """
            reply = Message(
                to=settings.agent_settings.bdi_core_agent_name + "@" + settings.agent_settings.host,
                body=msg,
            )
            await self.send(reply)
            self.agent.logger.info("Reply sent to BDI Core Agent")

        async def _query_llm(self, prompt: str) -> str:
            """
            Sends a chat completion request to the local LLM service.

            :param prompt: Input text prompt to pass to the LLM.
            :return: LLM-generated content or fallback message.
            """
            async with httpx.AsyncClient(timeout=120.0) as client:
                # Example dynamic content for future (optional)

                instructions = LLMInstructions()
                developer_instruction = instructions.build_developer_instruction()

                response = await client.post(
                    settings.llm_settings.local_llm_url,
                    headers={"Content-Type": "application/json"},
                    json={
                        "model": settings.llm_settings.local_llm_model,
                        "messages": [
                            {"role": "developer", "content": developer_instruction},
                            {"role": "user", "content": prompt},
                        ],
                        "temperature": 0.3,
                    },
                )

                try:
                    response.raise_for_status()
                    data: dict[str, Any] = response.json()
                    return (
                        data.get("choices", [{}])[0]
                        .get("message", {})
                        .get("content", "No response")
                    )
                except httpx.HTTPError as err:
                    self.agent.logger.error("HTTP error: %s", err)
                    return "LLM service unavailable."
                except Exception as err:
                    self.agent.logger.error("Unexpected error: %s", err)
                    return "Error processing the request."

    async def setup(self):
        """
        Sets up the SPADE behaviour to filter and process messages from the
        BDI Core Agent.
        """
        self.logger.info("LLMAgent setup complete")

        behaviour = self.ReceiveMessageBehaviour()
        self.add_behaviour(behaviour)
