"""Smart tasks set timers to turn on/off lights in various ways.

> Currently supporting wake up

SmartTask # return top level info
    TaskControl # Change top level values
    StartAction # Get top level info on start action
        StartActionItem # Get info on specific device in task
            StartActionItemController # change values for task
"""

import datetime
from datetime import datetime as dt

from .command import Command
from .const import (
    ATTR_DEVICE_STATE,
    ATTR_ID,
    ATTR_LIGHT_DIMMER,
    ATTR_REPEAT_DAYS,
    ATTR_SMART_TASK_LIGHTS_OFF,
    ATTR_SMART_TASK_NOT_AT_HOME,
    ATTR_SMART_TASK_TRIGGER_TIME_INTERVAL,
    ATTR_SMART_TASK_TRIGGER_TIME_START_HOUR,
    ATTR_SMART_TASK_TRIGGER_TIME_START_MIN,
    ATTR_SMART_TASK_TYPE,
    ATTR_SMART_TASK_WAKE_UP,
    ATTR_START_ACTION,
    ATTR_TRANSITION_TIME,
    ROOT_SMART_TASKS,
    ROOT_START_ACTION,
)
from .resource import ApiResource
from .util import BitChoices

WEEKDAYS = BitChoices(
    (
        ("mon", "Monday"),
        ("tue", "Tuesday"),
        ("wed", "Wednesday"),
        ("thu", "Thursday"),
        ("fri", "Friday"),
        ("sat", "Saturday"),
        ("sun", "Sunday"),
    )
)


class SmartTask(ApiResource):
    """Represent a smart task."""

    def __init__(self, gateway, raw):
        """Initialize the class."""
        super().__init__(raw)
        self._gateway = gateway

    @property
    def path(self):
        """Return gateway path."""
        return [ROOT_SMART_TASKS, self.id]

    @property
    def state(self):
        """Boolean representing the light state of the transition."""
        return self.raw.get(ATTR_DEVICE_STATE) == 1

    @property
    def task_type_id(self):
        """Return type of task."""
        return self.raw.get(ATTR_SMART_TASK_TYPE)

    @property
    def task_type_name(self):
        """Return the task type in plain text.

        (Own interpretation of names.)
        """
        if self.is_wake_up:
            return "Wake Up"
        if self.is_not_at_home:
            return "Not At Home"
        if self.is_lights_off:
            return "Lights Off"
        return None

    @property
    def is_wake_up(self):
        """Boolean representing if this is a wake up task."""
        return self.raw.get(ATTR_SMART_TASK_TYPE) == ATTR_SMART_TASK_WAKE_UP

    @property
    def is_not_at_home(self):
        """Boolean representing if this is a not home task."""
        return self.raw.get(ATTR_SMART_TASK_TYPE) == ATTR_SMART_TASK_NOT_AT_HOME

    @property
    def is_lights_off(self):
        """Boolean representing if this is a lights off task."""
        return self.raw.get(ATTR_SMART_TASK_TYPE) == ATTR_SMART_TASK_LIGHTS_OFF

    @property
    def repeat_days(self):
        """Return int (bit) for enabled weekdays."""
        return self.raw.get(ATTR_REPEAT_DAYS)

    @property
    def repeat_days_list(self):
        """Binary representation of weekdays the event takes place."""
        return WEEKDAYS.get_selected_values(self.raw.get(ATTR_REPEAT_DAYS))

    @property
    def task_start_parameters(self):
        """Return hour and minute that task starts."""
        return self.raw.get(ATTR_SMART_TASK_TRIGGER_TIME_INTERVAL)[0]

    @property
    def task_start_time(self):
        """Return the time the task starts.

        Time is set according to iso8601.
        """
        return datetime.time(
            self.task_start_parameters[ATTR_SMART_TASK_TRIGGER_TIME_START_HOUR],
            self.task_start_parameters[ATTR_SMART_TASK_TRIGGER_TIME_START_MIN],
        )

    @property
    def task_control(self):
        """Control a task."""
        return TaskControl(self, self.state, self.path, self._gateway)

    @property
    def start_action(self):
        """Return start action object."""
        return StartAction(self, self.path)

    def __repr__(self):
        """Return a readable name for smart task."""
        state = "on" if self.state else "off"
        return f"<Task {self.id} - {self.task_type_name} - {state}>"


class TaskControl:
    """Class to control the tasks."""

    def __init__(self, task, state, path, gateway):
        """Initialize TaskControl."""
        self._task = task
        self.state = state
        self.path = path
        self._gateway = gateway

    @property
    def tasks(self):
        """Return task objects of the task control."""
        return [
            StartActionItem(self._task, i, self.state, self.path, self.raw)
            for i in range(len(self.raw))
        ]

    def set_dimmer_start_time(self, hour, minute):
        """Set start time for task (hh:mm) in iso8601.

        NB: dimmer starts 30 mins before time in app
        """
        #  This is to calculate the difference between local time
        #  and the time in the gateway
        d_now = self._gateway.get_gateway_info().current_time
        d_utcnow = dt.utcnow()
        diff = d_now - d_utcnow
        newtime = dt(100, 1, 1, hour, minute, 00) - diff

        command = {
            ATTR_SMART_TASK_TRIGGER_TIME_INTERVAL: [
                {
                    ATTR_SMART_TASK_TRIGGER_TIME_START_HOUR: newtime.hour,
                    ATTR_SMART_TASK_TRIGGER_TIME_START_MIN: newtime.minute,
                }
            ]
        }
        return self._task.set_values(command)

    @property
    def raw(self):
        """Return raw data that it represents."""
        return self._task.raw[ATTR_START_ACTION]


class StartAction:
    """Class to control the start action-node."""

    def __init__(self, start_action, path):
        """Initialize StartAction class."""
        self.start_action = start_action
        self.path = path

    @property
    def state(self):
        """Return state of start action task."""
        return self.raw.get(ATTR_DEVICE_STATE)

    @property
    def devices(self):
        """Return state of start action task."""
        return [
            StartActionItem(self.start_action, i, self.state, self.path, self.raw)
            for i in range(len(self.raw[ROOT_START_ACTION]))
        ]

    @property
    def raw(self):
        """Return raw data that it represents."""
        return self.start_action.raw[ATTR_START_ACTION]


class StartActionItem:
    """Class to show settings for a task."""

    def __init__(self, task, index, state, path, raw):
        """Initialize TaskInfo."""
        self.task = task
        self.index = index
        self.state = state
        self.path = path
        self._raw = raw

    @property
    def devices_dict(self):
        """Return state of start action task."""
        json_list = {}
        index = 0
        for x_entry in self._raw[ROOT_START_ACTION]:
            if index != self.index:
                json_list.update(x_entry)
            index = index + 1
        return json_list

    @property
    def id(self):
        """Return ID (device id) of task."""
        return self.raw.get(ATTR_ID)

    @property
    def item_controller(self):
        """Control a task."""
        return StartActionItemController(
            self, self.raw, self.state, self.path, self.devices_dict
        )

    @property
    def transition_time(self):
        """Transition runs for this long from the time in task_start.

        Value is in seconds x 10. Default to 0 if transition is missing.
        """
        return self.raw.get(ATTR_TRANSITION_TIME, 0) / 60 / 10

    @property
    def dimmer(self):
        """Return dimmer level."""
        return self.raw.get(ATTR_LIGHT_DIMMER)

    @property
    def raw(self):
        """Return raw data that it represents."""
        return self._raw[ROOT_START_ACTION][self.index]

    def __repr__(self):
        """Return a readable name for this class."""
        return f"<StartActionItem (Device: {self.id} - Dimmer: {self.dimmer} - Time: {self.transition_time})>"


class StartActionItemController:
    """Class to edit settings for a task."""

    def __init__(self, item, raw, state, path, devices_dict):
        """Initialize TaskControl."""
        self._item = item
        self.raw = raw
        self.state = state
        self.path = path
        self.devices_dict = devices_dict

    def set_dimmer(self, dimmer):
        """Set final dimmer value for task."""
        command = {
            ATTR_START_ACTION: {
                ATTR_DEVICE_STATE: self.state,
                ROOT_START_ACTION: [
                    {
                        ATTR_ID: self.raw[ATTR_ID],
                        ATTR_LIGHT_DIMMER: dimmer,
                        ATTR_TRANSITION_TIME: self.raw.get(ATTR_TRANSITION_TIME, 0),
                    },
                    self.devices_dict,
                ],
            }
        }
        return self.set_values(command)

    def set_transition_time(self, transition_time):
        """Set time (mins) for light transition."""
        command = {
            ATTR_START_ACTION: {
                ATTR_DEVICE_STATE: self.state,
                ROOT_START_ACTION: [
                    {
                        ATTR_ID: self.raw[ATTR_ID],
                        ATTR_LIGHT_DIMMER: self.raw[ATTR_LIGHT_DIMMER],
                        ATTR_TRANSITION_TIME: transition_time * 10 * 60,
                    },
                    self.devices_dict,
                ],
            }
        }
        return self.set_values(command)

    def set_values(self, command):
        """
        Set values on task control.

        Returns a Command.
        """
        return Command("put", self._item.path, command)
