import json
import logging

import zmq
from spade.agent import Agent
from spade.behaviour import CyclicBehaviour

from control_backend.core.config import settings
from control_backend.core.zmq_context import context
from control_backend.schemas.ri_message import SpeechCommand

logger = logging.getLogger(__name__)


class RICommandAgent(Agent):
    subsocket: zmq.Socket
    pubsocket: zmq.Socket
    address = ""
    bind = False

    def __init__(
        self,
        jid: str,
        password: str,
        port: int = 5222,
        verify_security: bool = False,
        address="tcp://localhost:0000",
        bind=False,
    ):
        super().__init__(jid, password, port, verify_security)
        self.address = address
        self.bind = bind

    class SendCommandsBehaviour(CyclicBehaviour):
        async def run(self):
            """
            Run the command publishing loop indefinetely.
            """
            assert self.agent is not None
            # Get a message internally (with topic command)
            topic, body = await self.agent.subsocket.recv_multipart()

            # Try to get body
            try:
                body = json.loads(body)
                message = SpeechCommand.model_validate(body)

                # Send to the robot.
                await self.agent.pubsocket.send_json(message.model_dump())
            except Exception as e:
                logger.error("Error processing message: %s", e)

    async def setup(self):
        """
        Setup the command agent
        """
        logger.info("Setting up %s", self.jid)

        # To the robot
        self.pubsocket = context.socket(zmq.PUB)
        if self.bind:
            self.pubsocket.bind(self.address)
        else:
            self.pubsocket.connect(self.address)

        # Receive internal topics regarding commands
        self.subsocket = context.socket(zmq.SUB)
        self.subsocket.connect(settings.zmq_settings.internal_comm_address)
        self.subsocket.setsockopt(zmq.SUBSCRIBE, b"command")

        # Add behaviour to our agent
        commands_behaviour = self.SendCommandsBehaviour()
        self.add_behaviour(commands_behaviour)

        logger.info("Finished setting up %s", self.jid)
