# -*- coding: utf-8 -*-
"""Command sequence to test the HeaterHandler
@author J. Meier
@date   30.01.2021
"""
import enum

from config.definitions import CustomServiceList
from config.object_ids import get_object_ids
from tmtccmd.utility.obj_id import ObjectId
from tmtccmd.config.definitions import QueueCommands, ServiceOpCodeDictT
from tmtccmd.tc.pus_201_fsfw_health import (
    pack_set_health_cmd_data,
    FsfwHealth,
    Subservices,
)
from tmtccmd.tc.pus_8_funccmd import generate_action_command
from tmtccmd.config.globals import add_service_op_code_entry, add_op_code_entry
from tmtccmd.tc.packer import TcQueueT
from spacepackets.ecss.tc import PusTelecommand


class SwitchNumbers:
    HEATER_0_OBC_BRD = 0
    HEATER_1_PLOC_PROC_BRD = 1
    HEATER_2_ACS_BRD = 2
    HEATER_3_PCDU_PDU = 3
    HEATER_4_CAMERA = 4
    HEATER_5_STR = 5
    HEATER_6_DRO = 6
    HEATER_7_HPA = 7
    NUMBER_OF_SWITCHES = 8


class OpCodes:
    HEATER_CMD = ["0", "switch-cmd"]
    HEATER_EXT_CTRL = ["1", "set-ext-ctrl"]
    HEATER_FAULTY_CMD = ["2", "set-faulty"]
    HEATER_HEALTHY_CMD = ["3", "set-healthy"]


class Info:
    HEATER_CMD = "Heater Switch Command"
    HEATER_EXT_CTRL = "Set to external control"
    HEATER_FAULTY_CMD = "Set to faulty"
    HEATER_HEALTHY_CMD = "Set to healthy"


# Needed in OBSW to differentiate between external and internal heater commands
COMMAND_SOURCE_PARAM_EXTERNAL = 1


class ActionIds(enum.IntEnum):
    SWITCH_HEATER = 0


def add_heater_cmds(cmd_dict: ServiceOpCodeDictT):
    op_code_dict = dict()
    add_op_code_entry(
        op_code_dict=op_code_dict, keys=OpCodes.HEATER_CMD, info=Info.HEATER_CMD
    )
    add_op_code_entry(
        op_code_dict=op_code_dict,
        keys=OpCodes.HEATER_HEALTHY_CMD,
        info=Info.HEATER_HEALTHY_CMD,
    )
    add_op_code_entry(
        op_code_dict=op_code_dict,
        keys=OpCodes.HEATER_EXT_CTRL,
        info=Info.HEATER_EXT_CTRL,
    )
    add_op_code_entry(
        op_code_dict=op_code_dict,
        keys=OpCodes.HEATER_FAULTY_CMD,
        info=Info.HEATER_FAULTY_CMD,
    )
    add_service_op_code_entry(
        srv_op_code_dict=cmd_dict,
        name=CustomServiceList.HEATER.value,
        info="Heater Device",
        op_code_entry=op_code_dict,
    )


def pack_heater_cmds(object_id: bytearray, op_code: str, tc_queue: TcQueueT):
    if op_code in OpCodes.HEATER_CMD:
        tc_queue.appendleft((QueueCommands.PRINT, "Heater Switching"))
        heater_number = prompt_heater()
        while True:
            action = input("Turn switch on or off? (0 - off, 1 - on): ")
            if not action.isdigit():
                print("Switch action not valid")
                continue
            action = int(action)
            if action != 0 and action != 1:
                print("Invalid action defined. Must be 0 (off) or 1 (on")
                continue
            break
        if action == 1:
            act_str = "on"
        else:
            act_str = "off"
        debug_string = f"Switching heater {heater_number} {act_str}"
        tc_queue.appendleft((QueueCommands.PRINT, debug_string))
        command = pack_switch_heater_command(object_id, heater_number, action)
        tc_queue.appendleft(command.pack_command_tuple())
    if op_code in OpCodes.HEATER_EXT_CTRL:
        heater_number = prompt_heater()
        obj_id = heater_idx_to_obj(heater_number)
        health_cmd(
            tc_queue=tc_queue,
            object_id=obj_id,
            health=FsfwHealth.EXTERNAL_CTRL,
            health_str="External Control",
            heater_idx=heater_number,
        )
    if op_code in OpCodes.HEATER_FAULTY_CMD:
        heater_number = prompt_heater()
        obj_id = heater_idx_to_obj(heater_number)
        health_cmd(
            tc_queue=tc_queue,
            object_id=obj_id,
            health=FsfwHealth.FAULTY,
            health_str="Faulty",
            heater_idx=heater_number,
        )
    if op_code in OpCodes.HEATER_HEALTHY_CMD:
        heater_number = prompt_heater()
        obj_id = heater_idx_to_obj(heater_number)
        health_cmd(
            tc_queue=tc_queue,
            object_id=obj_id,
            health=FsfwHealth.HEALTHY,
            health_str="Healthy",
            heater_idx=heater_number,
        )


def heater_idx_to_obj(heater: int) -> ObjectId:
    from config.object_ids import (
        HEATER_0_OBC_BRD,
        HEATER_1_PLOC_PROC_BRD,
        HEATER_2_ACS_BRD,
        HEATER_3_PCDU_BRD,
        HEATER_4_CAMERA,
        HEATER_5_STR,
        HEATER_6_DRO,
        HEATER_7_HPA,
    )

    obj_id_array = [
        HEATER_0_OBC_BRD,
        HEATER_1_PLOC_PROC_BRD,
        HEATER_2_ACS_BRD,
        HEATER_3_PCDU_BRD,
        HEATER_4_CAMERA,
        HEATER_5_STR,
        HEATER_6_DRO,
        HEATER_7_HPA,
    ]
    obj_dict = get_object_ids()
    obj_id_obj = obj_dict.get(obj_id_array[heater])
    if obj_id_obj is None:
        return ObjectId.from_bytes(obj_id_array[heater])
    return obj_id_obj


def prompt_heater() -> int:
    while True:
        print("HEATER 0 | PLOC PROC Board")
        print("HEATER 1 | PCDU Board")
        print("HEATER 2 | ACS Board")
        print("HEATER 3 | OBC Board")
        print("HEATER 4 | CAMERA")
        print("HEATER 5 | STR")
        print("HEATER 6 | DRO")
        print("HEATER 7 | HPA")
        heater_number = input("Type number of heater to switch [0-7]: ")
        if not heater_number.isdigit():
            print("Heater number not a digit")
            continue
        heater_number = int(heater_number)
        if heater_number >= SwitchNumbers.NUMBER_OF_SWITCHES or heater_number < 0:
            print("Invalid heater switch number")
            continue
        break
    return heater_number


def health_cmd(
    tc_queue: TcQueueT,
    heater_idx: int,
    object_id: ObjectId,
    health: FsfwHealth,
    health_str: str,
):
    tc_queue.appendleft(
        (
            QueueCommands.PRINT,
            f"Setting Heater {heater_idx} {object_id} to {health_str}",
        )
    )
    app_data = pack_set_health_cmd_data(object_id=object_id.as_bytes, health=health)
    cmd = PusTelecommand(
        service=201, subservice=Subservices.TC_SET_HEALTH, app_data=app_data
    )
    tc_queue.appendleft(cmd.pack_command_tuple())


def pack_switch_heater_command(
    object_id: bytes, switch_nr: int, switch_action: int
) -> PusTelecommand:
    """Function to generate a heater switch command.
    :param object_id: The object id of the HeaterHandler object.
    :param switch_nr: The switch number identifying the heater to switch
    :param switch_action: Action to perform. 0 - Sets switch off, 1 - Sets switch on.
    """
    command = bytearray()
    command.append(switch_nr)
    command.append(switch_action)
    command.append(COMMAND_SOURCE_PARAM_EXTERNAL)
    return generate_action_command(
        object_id=object_id, action_id=ActionIds.SWITCH_HEATER, app_data=command
    )