import threading
import pygame

from bluer_options.logger import get_logger
from bluer_sbc.joystick import Joystick

from bluer_ugv.swallow.session.classical.config.classes import ClassicalConfig
from bluer_ugv.swallow.session.classical.controller.classes import ClassicalController
from bluer_ugv.swallow.session.classical.ethernet.classes import ClassicalEthernet
from bluer_ugv.swallow.session.classical.controller.joystick.controls import Controls
from bluer_ugv.swallow.session.classical.leds import ClassicalLeds
from bluer_ugv.swallow.session.classical.mode import OperationMode
from bluer_ugv.swallow.session.classical.setpoint.classes import ClassicalSetPoint
from bluer_ugv import ICON

logger = get_logger(f"{ICON}  🕹️")


class ClassicalJoystick(ClassicalController):
    def __init__(
        self,
        config: ClassicalConfig,
        ethernet: ClassicalEthernet,
        leds: ClassicalLeds,
        setpoint: ClassicalSetPoint,
    ):
        super().__init__(
            config=config,
            ethernet=ethernet,
            leds=leds,
            setpoint=setpoint,
        )

        self.joystick = Joystick()

        self.controls = Controls

        self.running: bool = False

        if not self.joystick.enabled:
            return

        self.running = True
        self.thread = threading.Thread(target=self.loop, daemon=True)
        self.thread.start()

    def handle_axis(
        self,
        axis: int,
        value: float,
    ):
        if axis in self.controls["axes"]:
            self.special_key = False

            axis_name, axis_direction = self.controls["axes"][axis]
            self.setpoint.put(
                what=axis_name,
                value=axis_direction * int(100 * value),
            )

    def handle_button(self, button: int):
        # bash keys
        if self.special_key:
            if button in self.controls["special-buttons"]:
                event = self.controls["special-buttons"][button]
                self.reply_to_bash(event)
                self.config.set("stop-requested", True)

        if button in self.controls["buttons"]:
            event = self.controls["buttons"][button]

            # ultrasonic
            if event == "ultrasonic off":
                self.set_ultrasonic(False)
            if event == "ultrasonic on":
                self.set_ultrasonic(True)

            # debug
            if event == "debug on":
                self.set_debug(True)
            if event == "debug off":
                self.set_debug(False)

            # mode
            mode = self.config.get("mode")
            updated_mode = mode
            if event == "mode = none":
                updated_mode = OperationMode.NONE

            if event == "mode = action":
                updated_mode = OperationMode.ACTION

            if event == "mode = training":
                updated_mode = OperationMode.TRAINING

            if mode != updated_mode:
                self.config.set("mode", updated_mode)
                self.special_key = False

            # stop
            if event == "stop":
                self.setpoint.stop()
                self.special_key = False

            # special key
            if event == "special key":
                self.set_special_key()

    def loop(self):
        logger.info(f"{self.__class__.__name__}.loop started.")

        while self.running:
            self.joystick.read_events()

            for event in self.joystick.buttons.values():
                if event.type == pygame.JOYBUTTONDOWN:
                    logger.info(
                        "{}: button {} pressed.".format(
                            self.__class__.__name__,
                            event.button,
                        )
                    )
                    self.handle_button(event.button)

            for event in self.joystick.axes.values():
                logger.info(
                    "{}: axis {} moved to {}.".format(
                        self.__class__.__name__,
                        event.axis,
                        event.value,
                    )
                )

                self.handle_axis(
                    axis=event.axis,
                    value=event.value,
                )

            if self.special_key:
                self.leds.flash_all()

            self.joystick.clock.tick(60)

    def stop(self):
        if not self.joystick.enabled:
            return

        self.running = False
        self.thread.join()

        logger.info(f"{self.__class__.__name__} stopped.")

        Joystick.cleanup()
