"""Vizio SmartCast API commands and class for individual item settings."""

from typing import Any, Dict, Optional, Union

from pyvizio.api._protocol import (
    ACTION_MODIFY,
    ENDPOINT,
    ITEM_CNAME,
    PATH_MODEL,
    ResponseKey,
)
from pyvizio.api.base import CommandBase, InfoCommandBase
from pyvizio.helpers import dict_get_case_insensitive, get_value_from_path


class GetDeviceInfoCommand(InfoCommandBase):
    """Command to get device info."""

    def __init__(self, device_type: str) -> None:
        """Initialize command to get device info."""
        super(GetDeviceInfoCommand, self).__init__(ENDPOINT[device_type]["DEVICE_INFO"])
        self.paths = PATH_MODEL[device_type]

    def process_response(self, json_obj: Dict[str, Any]) -> Dict[str, Any]:
        """Return response to command to get device info."""
        return dict_get_case_insensitive(json_obj, ResponseKey.ITEMS, [{}])[0]


class GetModelNameCommand(GetDeviceInfoCommand):
    """Command to get device model name."""

    def __init__(self, device_type: str) -> None:
        """Initialize command to get device model name."""
        super(GetModelNameCommand, self).__init__(device_type)

    def process_response(self, json_obj: Dict[str, Any]) -> Optional[str]:
        """Return response to command to get device model name."""
        return get_value_from_path(
            dict_get_case_insensitive(
                super(GetModelNameCommand, self).process_response(json_obj),
                ResponseKey.VALUE,
                {},
            ),
            self.paths,
        )


class Item(object):
    """Individual item setting."""

    def __init__(self, json_obj: Dict[str, Any]) -> None:
        """Initialize individual item setting."""
        self.id = None
        id = dict_get_case_insensitive(json_obj, ResponseKey.HASHVAL)
        if id is not None:
            self.id = int(id)

        self.c_name = dict_get_case_insensitive(json_obj, ResponseKey.CNAME)
        self.type = dict_get_case_insensitive(json_obj, ResponseKey.TYPE)
        self.name = dict_get_case_insensitive(json_obj, ResponseKey.NAME)
        self.value = dict_get_case_insensitive(json_obj, ResponseKey.VALUE)

        self.min = None
        min = dict_get_case_insensitive(json_obj, ResponseKey.MINIMUM)
        if min is not None:
            self.min = int(min)

        self.max = None
        max = dict_get_case_insensitive(json_obj, ResponseKey.MAXIMUM)
        if max is not None:
            self.max = int(max)

        self.center = None
        center = dict_get_case_insensitive(json_obj, ResponseKey.CENTER)
        if center is not None:
            self.center = int(center)

        self.choices = dict_get_case_insensitive(json_obj, ResponseKey.ELEMENTS, [])

    def __repr__(self) -> str:
        return f"{type(self).__name__}({self.__dict__})"

    def __eq__(self, other) -> bool:
        return self is other or (
            self.c_name == other.c_name
            and self.type == other.type
            and self.name == other.name
            and self.value == other.value
        )


class DefaultReturnItem(object):
    """Mock individual item setting response when item is not found."""

    def __init__(self, value: Any) -> None:
        """Initialize mock individual item setting response when item is not found."""
        self.value = value

    def __repr__(self) -> str:
        return f"{type(self).__name__}({self.__dict__})"

    def __eq__(self, other) -> bool:
        return self is other or self.__dict__ == other.__dict__


class ItemInfoCommandBase(InfoCommandBase):
    """Command to get individual item setting."""

    def __init__(
        self, device_type: str, item_name: str, default_return: Union[int, str] = None
    ) -> None:
        """Initialize command to get individual item setting."""
        super(ItemInfoCommandBase, self).__init__(ENDPOINT[device_type][item_name])
        self.item_name = item_name.upper()
        self.default_return = default_return

    def process_response(self, json_obj: Dict[str, Any]) -> Any:
        """Return response to command to get individual item setting."""
        items = [
            Item(item)
            for item in dict_get_case_insensitive(json_obj, ResponseKey.ITEMS, [])
        ]

        for itm in items:
            if itm.c_name.lower() in (
                ITEM_CNAME.get(self.item_name, ""),
                self.item_name,
            ) and (
                itm.value is not None
                or itm.center is not None
                or itm.choices is not None
            ):
                return itm

        if self.default_return is not None:
            return DefaultReturnItem(self.default_return)

        return None


class ItemCommandBase(CommandBase):
    """Command to set value of individual item setting."""

    def __init__(
        self, device_type: str, item_name: str, id: int, value: Union[int, str]
    ) -> None:
        """Initialize command to set value of individual item setting."""
        super(ItemCommandBase, self).__init__(ENDPOINT[device_type][item_name])
        self.item_name = item_name

        self.VALUE = value
        # noinspection SpellCheckingInspection
        self.HASHVAL = int(id)
        self.REQUEST = ACTION_MODIFY.upper()


class GetCurrentPowerStateCommand(ItemInfoCommandBase):
    """Command to get current power state of device."""

    def __init__(self, device_type: str) -> None:
        """Initialize command to get current power state of device."""
        super(GetCurrentPowerStateCommand, self).__init__(device_type, "POWER_MODE", 0)


class GetCurrentChargingStatusCommand(ItemInfoCommandBase):
    """Command to get current charging status of device."""

    def __init__(self, device_type: str) -> None:
        """Initialize command to get current charging status of device."""
        super(GetCurrentChargingStatusCommand, self).__init__(device_type, "CHARGING_STATUS", 0)


class GetBatteryLevelCommand(ItemInfoCommandBase):
    """Command to get current battery level (will be 0 if charging) of device."""

    def __init__(self, device_type: str) -> None:
        """Initialize command to get current battery level (will be 0 if charging) of device."""
        super(GetBatteryLevelCommand, self).__init__(device_type, "BATTERY_LEVEL", 0)


class GetESNCommand(ItemInfoCommandBase):
    """Command to get device ESN (electronic serial number?)."""

    def __init__(self, device_type: str) -> None:
        """Initialize command to get device ESN (electronic serial number?)."""
        super(GetESNCommand, self).__init__(device_type, "ESN")


class GetSerialNumberCommand(ItemInfoCommandBase):
    """Command to get device serial number."""

    def __init__(self, device_type: str) -> None:
        """Initialize command to get device serial number."""
        super(GetSerialNumberCommand, self).__init__(device_type, "SERIAL_NUMBER")


class GetVersionCommand(ItemInfoCommandBase):
    """Command to get SmartCast software version."""

    def __init__(self, device_type: str) -> None:
        """Initialize command to get SmartCast software version."""
        super(GetVersionCommand, self).__init__(device_type, "VERSION")


class AltItemInfoCommandBase(ItemInfoCommandBase):
    """Command to get individual item setting."""

    def __init__(
        self,
        device_type: str,
        endpoint_name: str,
        item_name: str,
        default_return: Union[int, str] = None,
    ) -> None:
        """Initialize command to get individual item setting."""
        super(ItemInfoCommandBase, self).__init__(ENDPOINT[device_type][endpoint_name])
        self.item_name = item_name.upper()
        self.default_return = default_return


class GetAltESNCommand(AltItemInfoCommandBase):
    """Command to get device ESN (electronic serial number?)."""

    def __init__(self, device_type: str) -> None:
        """Initialize command to get device ESN (electronic serial number?)."""
        super(GetAltESNCommand, self).__init__(device_type, "_ALT_ESN", "ESN")


class GetAltSerialNumberCommand(AltItemInfoCommandBase):
    """Command to get device serial number."""

    def __init__(self, device_type: str) -> None:
        """Initialize command to get device serial number."""
        super(GetAltSerialNumberCommand, self).__init__(
            device_type, "_ALT_SERIAL_NUMBER", "SERIAL_NUMBER"
        )


class GetAltVersionCommand(AltItemInfoCommandBase):
    """Command to get SmartCast software version."""

    def __init__(self, device_type: str) -> None:
        """Initialize command to get SmartCast software version."""
        super(GetAltVersionCommand, self).__init__(
            device_type, "_ALT_VERSION", "VERSION"
        )
