"""
Not1MM Contest logger
Email: michael.bridak@gmail.com
GPL V3
"""

import datetime
import logging

from PyQt6.QtCore import QEventLoop, QObject, QThread, pyqtSignal

from not1mm.lib.cat_fake import FakeCAT
from not1mm.lib.cat_flrig import FlrigCAT
from not1mm.lib.cat_rigctld import RigctldCAT
from not1mm.lib.cat_tci import TciCAT

logger = logging.getLogger("radio")


class Radio(QObject):
    """Radio class"""

    poll_callback = pyqtSignal(dict)
    vfoa = "14030000"
    mode = "CW"
    bw = "500"
    delta = 500
    poll_time = datetime.datetime.now(datetime.UTC) + datetime.timedelta(
        milliseconds=delta
    )
    time_to_quit = False
    online = False
    interface = None
    host = None
    port = None
    modes = ""
    cw_list = ["CW", "CW-L", "CW-U", "CWR", "CW-R"]  # noqa: RUF012
    rtty_list = [  # noqa: RUF012
        "RTTY",
        "DIGI-L",
        "PKTLSB",
        "LSB-D",
    ]
    last_data_mode = "RTTY"
    last_cw_mode = "CW"
    last_ph_mode = "SSB"

    def __init__(self, interface: str, host: str, port: int) -> None:
        super().__init__()
        """setup interface"""
        self.interface = interface
        self.host = host
        self.port = port
        logger.debug("Using %s: %s %d", interface, host, port)

        try:
            if self.interface == "flrig":
                self.cat = FlrigCAT(self.host, self.port)
            elif self.interface == "rigctld":
                self.cat = RigctldCAT(self.host, self.port)
            elif self.interface == "tci":
                self.cat = TciCAT(self.host, self.port)
            else:
                self.cat = FakeCAT(self.host, self.port)
            self.online = self.cat.online
            self.modes = self.cat.get_mode_list()
            for pos_cw in self.cw_list:
                if pos_cw in self.modes:
                    self.last_cw_mode = pos_cw
                    break
            for pos_rtty in self.rtty_list:
                if pos_rtty in self.modes:
                    self.last_data_mode = pos_rtty
                    break
        except ConnectionResetError:
            ...

    def run(self):
        while not self.time_to_quit:
            if datetime.datetime.now(datetime.UTC) > self.poll_time:
                self.poll_time = datetime.datetime.now(
                    datetime.UTC
                ) + datetime.timedelta(milliseconds=self.delta)
                vfoa = self.cat.get_vfo()
                self.online = False
                if vfoa:
                    if not vfoa.isnumeric():
                        logger.debug(f"Bad VFOA data {vfoa=}")
                        continue
                    self.vfoa = vfoa
                    self.online = True
                mode = self.cat.get_mode()
                if mode:
                    self.mode = mode
                    self.store_last_data_mode(mode)
                    self.online = True
                bw = self.cat.get_bw()
                if bw:
                    self.bw = bw
                    self.online = True
                try:
                    self.poll_callback.emit(
                        {
                            "vfoa": self.vfoa,
                            "mode": self.mode,
                            "bw": self.bw,
                            "online": self.cat.online,
                        }
                    )
                except QEventLoop:
                    ...
            QThread.msleep(100)
        # Backends owning their own threads (TCI) must be torn down here, or
        # the app hangs on exit. The others have no close() and no-op.
        close = getattr(self.cat, "close", None)
        if close is not None:
            close()

    def store_last_data_mode(self, the_mode: str = ""):
        """if the last mode is a data mode, save it."""
        # QMX ['CW-U', 'CW-L', 'DIGI-U', 'DIGI-L']
        # 7300 ['LSB', 'USB', 'AM', 'FM', 'CW', 'CW-R', 'RTTY', 'RTTY-R', 'LSB-D', 'USB-D', 'AM-D', 'FM-D']
        datamodes = [
            "RTTY",
            "RTTY-R",
            "LSB-D",
            "USB-D",
            "AM-D",
            "FM-D",
            "FSK",
            "DIGI-U",
            "DIGI-L",
            "RTTYR",
            "PKTLSB",
            "PKTUSB",
        ]
        if the_mode in datamodes:
            self.last_data_mode = the_mode

        cwmodes = ["CW", "CW-L", "CW-U", "CWR"]

        if the_mode in cwmodes:
            self.last_cw_mode = the_mode

    def sendvoicememory(self, memoryspot=1):
        """..."""
        if self.cat:
            self.cat.sendvoicememory(memoryspot)

    def sendcw(self, texttosend):
        """..."""
        logger.debug(f"Send CW: {texttosend}")
        if self.cat:
            self.cat.sendcw(texttosend)

    def stopcw(self):
        logger.debug("Stopping CW")
        if self.cat:
            self.cat.stopcw()

    def set_cw_speed(self, speed):
        logger.debug("Setting CW speed %d", speed)
        if self.cat:
            self.cat.set_cw_speed(speed)

    def set_cw_send(self, send: bool) -> None:
        logger.debug("Setting CW send %s", send)
        if self.cat:
            self.cat.set_cw_send(send)

    def set_vfo(self, vfo):
        self.vfoa = vfo

        if self.cat:
            self.cat.set_vfo(vfo)

        self.poll_time = datetime.datetime.now(datetime.UTC)

    def set_mode(self, mode):
        self.mode = mode
        if self.cat:
            self.cat.set_mode(mode)
        self.poll_time = datetime.datetime.now(datetime.UTC)

    def get_modes(self):
        """get list of modes"""
        return self.modes

    def get_last_data_mode(self):
        """gets last used data mode."""
        return self.last_data_mode

    def ptt_on(self):
        if self.cat:
            self.cat.ptt_on()

    def ptt_off(self):
        if self.cat:
            self.cat.ptt_off()

    def get_ptt(self):
        """Get PTT state from radio"""
        if self.cat:
            return self.cat.get_ptt()
        return 0
