import enum
import struct

from eive_tmtc.pus_tm.defs import PrintWrapper
from spacepackets.ecss import PusTelecommand

from eive_tmtc.config.definitions import CustomServiceList
from eive_tmtc.config.object_ids import BPX_HANDLER_ID
from tmtccmd.config.tmtc import (
    tmtc_definitions_provider,
    TmtcDefinitionWrapper,
    OpCodeEntry,
)
from tmtccmd.tc import service_provider
from tmtccmd.tc.decorator import ServiceProviderParams
from tmtccmd.pus.s8_fsfw_funccmd import create_action_cmd
from tmtccmd.tc.pus_3_fsfw_hk import generate_one_hk_command, make_sid
from tmtccmd.tc.pus_200_fsfw_mode import pack_mode_data, Mode
from tmtccmd.tc.pus_200_fsfw_mode import Subservice as ModeSubservices
from tmtccmd.util.tmtc_printer import FsfwTmTcPrinter


class BpxSetId(enum.IntEnum):
    GET_HK_SET = 0
    GET_CFG_SET = 5


class BpxActionId:
    REBOOT = 2
    RESET_COUNTERS = 3
    SET_CFG = 4
    GET_CFG = 5


class BpxOpCode:
    HK = ["0", "hk"]
    OFF = ["off"]
    ON = ["on"]
    RST_BOOT_CNT = ["1", "rst_boot_cnt"]
    REQUEST_CFG = ["2", "cfg"]
    REQUEST_CFG_HK = ["3", "cfg_hk"]
    REBOOT = ["4", "reboot"]


@tmtc_definitions_provider
def add_bpx_cmd_definitions(defs: TmtcDefinitionWrapper):
    oce = OpCodeEntry()
    oce.add(keys=BpxOpCode.ON, info="On command")
    oce.add(keys=BpxOpCode.OFF, info="Off command")
    oce.add(keys=BpxOpCode.HK, info="Request BPX HK")
    oce.add(keys=BpxOpCode.RST_BOOT_CNT, info="Reset Boot Count")
    oce.add(keys=BpxOpCode.REQUEST_CFG, info="Request Configuration Struct (Step 1)")
    oce.add(
        keys=BpxOpCode.REQUEST_CFG_HK, info="Request Configuration Struct HK (Step 2)"
    )
    oce.add(keys=BpxOpCode.REBOOT, info="Reboot Command")
    defs.add_service(
        name=CustomServiceList.BPX_BATTERY.value,
        info="BPX Battery Handler",
        op_code_entry=oce,
    )


@service_provider(CustomServiceList.BPX_BATTERY.value)
def pack_bpx_commands(p: ServiceProviderParams):
    op_code = p.op_code
    q = p.queue_helper
    if op_code in BpxOpCode.HK:
        q.add_log_cmd("Requesting BPX battery HK set")
        sid = make_sid(object_id=BPX_HANDLER_ID, set_id=BpxSetId.GET_HK_SET)
        q.add_pus_tc(generate_one_hk_command(sid=sid))
    if op_code in BpxOpCode.OFF:
        q.add_log_cmd("Off mode")
        mode_cmd = pack_mode_data(BPX_HANDLER_ID, Mode.OFF, 0)
        q.add_pus_tc(
            PusTelecommand(
                service=200,
                subservice=ModeSubservices.TC_MODE_COMMAND,
                app_data=mode_cmd,
            )
        )
    if op_code in BpxOpCode.ON:
        q.add_log_cmd("On mode")
        mode_cmd = pack_mode_data(BPX_HANDLER_ID, Mode.ON, 0)
        q.add_pus_tc(
            PusTelecommand(
                service=200,
                subservice=ModeSubservices.TC_MODE_COMMAND,
                app_data=mode_cmd,
            )
        )
    if op_code in BpxOpCode.RST_BOOT_CNT:
        q.add_log_cmd("Resetting reboot counters")
        q.add_pus_tc(
            create_action_cmd(
                object_id=BPX_HANDLER_ID, action_id=BpxActionId.RESET_COUNTERS
            )
        )
    if op_code in BpxOpCode.REQUEST_CFG:
        q.add_log_cmd("Requesting configuration struct")
        q.add_pus_tc(
            create_action_cmd(object_id=BPX_HANDLER_ID, action_id=BpxActionId.GET_CFG)
        )
    if op_code in BpxOpCode.REQUEST_CFG_HK:
        q.add_log_cmd("Requesting configuration struct HK")
        sid = make_sid(object_id=BPX_HANDLER_ID, set_id=BpxSetId.GET_CFG_SET)
        q.add_pus_tc(generate_one_hk_command(sid=sid))
    if op_code in BpxOpCode.REBOOT:
        q.add_log_cmd("Rebooting BPX battery")
        q.add_pus_tc(
            create_action_cmd(object_id=BPX_HANDLER_ID, action_id=BpxActionId.REBOOT)
        )


HEADER_LIST = [
    "Charge Current",
    "Discharge Current",
    "Heater Current",
    "Battery Voltage",
    "Batt Temp 1",
    "Batt Temp 2",
    "Batt Temp 3",
    "Batt Temp 4",
    "Reboot Counter",
    "Boot Cause",
]


def handle_bpx_hk_data(printer: FsfwTmTcPrinter, set_id: int, hk_data: bytes):
    pw = PrintWrapper(printer)
    if set_id == BpxSetId.GET_HK_SET:
        fmt_str = "!HHHHhhhhIB"
        inc_len = struct.calcsize(fmt_str)
        (
            charge_current,
            discharge_current,
            heater_current,
            batt_voltage,
            batt_temp_1,
            batt_temp_2,
            batt_temp_3,
            batt_temp_4,
            reboot_cntr,
            boot_cause,
        ) = struct.unpack(fmt_str, hk_data[0:inc_len])
        content_list = [
            charge_current,
            discharge_current,
            heater_current,
            batt_voltage,
            batt_temp_1,
            batt_temp_2,
            batt_temp_3,
            batt_temp_4,
            reboot_cntr,
            boot_cause,
        ]
        validity_buffer = hk_data[inc_len:]
        pw.dlog(str(HEADER_LIST))
        pw.dlog(str(content_list))
        printer.print_validity_buffer(validity_buffer=validity_buffer, num_vars=10)
    elif set_id == BpxSetId.GET_CFG_SET:
        battheat_mode = hk_data[0]
        battheat_low = struct.unpack("!b", hk_data[1:2])[0]
        battheat_high = struct.unpack("!b", hk_data[2:3])[0]
        header_list = [
            "Battery Heater Mode",
            "Battery Heater Low Limit",
            "Battery Heater High Limit",
        ]
        content_list = [battheat_mode, battheat_low, battheat_high]
        validity_buffer = hk_data[3:]
        pw.dlog(str(header_list))
        pw.dlog(str(content_list))
        printer.print_validity_buffer(validity_buffer=validity_buffer, num_vars=10)