import enum
import logging
import time
from pathlib import Path

from dut.dut_controller import DutController

from .test_scenario import TestScenario

SKIP_CHARGING = False
SKIP_RELAXING = False
SKIP_DISCHARGING = False


class ScenarioPhase(enum.Enum):
    NOT_STARTED = 0
    CHARGING = 1
    CHARGED_RELAXING = 2
    DISCHARGING = 3
    DISCHARGED_RELAXING = 4
    DONE = 5


class LinearScenario(TestScenario):

    def __init__(
        self, discharge_load: int = 100, relaxation_time_min: int = 60
    ) -> None:

        # DUT use display backlight intensity to change its load (discharge
        # current). Backlight intensity could be set in range of 0-255, but
        # there is no direct translation into discharge current.
        # Typically the discharge current is ~aprx 80mA with backlight set to 0
        # and 220mA when set to max 225.
        self.discharge_load = discharge_load
        self.relaxation_time_min = relaxation_time_min
        self.phase_start = time.time()
        self.remaining_time = time.time()
        self.scenario_phase = ScenarioPhase.NOT_STARTED
        self.time_id = "0000000000"
        self.previous_phase = ScenarioPhase.NOT_STARTED

    def setup(self, dut_controller: DutController) -> None:

        # Start with charging phase first, so connect the charger with relay
        # and enable the charging.
        self.scenario_phase = ScenarioPhase.CHARGING
        dut_controller.power_up_all()  # Power up all DUTs

        # Wait for DUTs to power up
        time.sleep(3)

        dut_controller.set_backlight(150)
        dut_controller.set_soc_limit(100)
        dut_controller.enable_charging()
        time.sleep(1)  # Give some time for the command to be processed

        self.phase_start = time.time()
        self.test_time_id = f"{time.strftime('%y%m%d%H%M')}"

    def run(self, dut_controller: DutController) -> bool:

        if self.previous_phase != self.scenario_phase:
            logging.info(f"Linear scenario entered {self.scenario_phase} phase.")
            self.previous_phase = self.scenario_phase

        # Charge until all DuT is above certain voltage threshold and charging
        # state is IDLE (means that PMIC automatically stopped charging)
        # Move to next phase when all DUTs are charged.
        if self.scenario_phase == ScenarioPhase.CHARGING:

            if dut_controller.all_duts_charged() or SKIP_CHARGING:
                self.scenario_phase = ScenarioPhase.CHARGED_RELAXING
                self.phase_start = time.time()

        # Relax
        elif self.scenario_phase == ScenarioPhase.CHARGED_RELAXING:

            # Relaxation time is set in minutes, so convert to seconds
            if (time.time() - self.phase_start) >= (
                self.relaxation_time_min * 60
            ) or SKIP_RELAXING:

                dut_controller.power_down_all()
                dut_controller.set_backlight(self.discharge_load)
                self.scenario_phase = ScenarioPhase.DISCHARGING
                self.phase_start = time.time()

            else:

                elapsed_min = int((time.time() - self.phase_start) / 60)

                if self.remaining_time != self.relaxation_time_min - elapsed_min:
                    # Update remaining time only if it changed
                    self.remaining_time = self.relaxation_time_min - elapsed_min
                    logging.info(
                        f"Relaxing for {self.relaxation_time_min} minutes, remaining: {self.remaining_time} minutes"
                    )

        elif self.scenario_phase == ScenarioPhase.DISCHARGING:

            if dut_controller.all_duts_discharged() or SKIP_DISCHARGING:

                self.scenario_phase = ScenarioPhase.DISCHARGED_RELAXING
                self.phase_start = time.time()

        elif self.scenario_phase == ScenarioPhase.DISCHARGED_RELAXING:

            # Relaxation time is set in minutes, so convert to seconds
            if (time.time() - self.phase_start) >= (
                self.relaxation_time_min * 60
            ) or SKIP_RELAXING:

                self.scenario_phase = ScenarioPhase.DONE
                logging.info("Scenario completed successfully.")
                return True

            else:
                elapsed_min = int((time.time() - self.phase_start) / 60)

                if self.remaining_time != self.relaxation_time_min - elapsed_min:
                    # Update remaining time only if it changed
                    self.remaining_time = self.relaxation_time_min - elapsed_min
                    logging.info(
                        f"Relaxing for {self.relaxation_time_min} minutes, remaining: {self.remaining_time} minutes"
                    )

        # Relax
        return False

    def log_data(
        self, dut_controller: DutController, output_directory: Path, temp: float
    ) -> None:

        dut_controller.log_data(
            output_directory,
            self.test_time_id,
            "linear",
            self.scenario_phase.name.lower(),
            temp,
        )

    def teardown(self, dut_controller: DutController) -> None:
        pass
