"""Python interface for TP-Link's smart home devices.

All common, shared functionalities are available through `Device` class::

>>> from kasa import Discover
>>> x = await Discover.discover_single("192.168.1.1")
>>> print(x.model)

For device type specific actions `modules` and `features` should be used instead.

Module-specific errors are raised as `KasaException` and are expected
to be handled by the user of the library.
"""

from importlib.metadata import version
from typing import TYPE_CHECKING, Any
from warnings import warn

from kasa.credentials import Credentials
from kasa.device import Device
from kasa.device_type import DeviceType
from kasa.deviceconfig import (
    DeviceConfig,
    DeviceConnectionParameters,
    DeviceEncryptionType,
    DeviceFamily,
)
from kasa.discover import Discover
from kasa.emeterstatus import EmeterStatus
from kasa.exceptions import (
    AuthenticationError,
    DeviceError,
    KasaException,
    TimeoutError,
    UnsupportedDeviceError,
)
from kasa.feature import Feature
from kasa.interfaces.light import HSV, ColorTempRange, Light, LightState
from kasa.interfaces.thermostat import Thermostat, ThermostatState
from kasa.module import Module
from kasa.protocols import BaseProtocol, IotProtocol, SmartCamProtocol, SmartProtocol
from kasa.protocols.iotprotocol import _deprecated_TPLinkSmartHomeProtocol  # noqa: F401
from kasa.smartcam.modules.camera import StreamResolution
from kasa.transports import BaseTransport

__version__ = version("python-kasa")


__all__ = [
    "Discover",
    "BaseProtocol",
    "BaseTransport",
    "IotProtocol",
    "SmartProtocol",
    "SmartCamProtocol",
    "LightState",
    "TurnOnBehaviors",
    "TurnOnBehavior",
    "DeviceType",
    "Feature",
    "EmeterStatus",
    "Device",
    "Light",
    "ColorTempRange",
    "HSV",
    "Plug",
    "Module",
    "KasaException",
    "AuthenticationError",
    "DeviceError",
    "UnsupportedDeviceError",
    "TimeoutError",
    "Credentials",
    "DeviceConfig",
    "DeviceConnectionParameters",
    "DeviceEncryptionType",
    "DeviceFamily",
    "ThermostatState",
    "Thermostat",
    "StreamResolution",
]

from . import iot
from .iot.modules.lightpreset import IotLightPreset

deprecated_names = ["TPLinkSmartHomeProtocol"]
deprecated_smart_devices = {
    "SmartDevice": iot.IotDevice,
    "SmartPlug": iot.IotPlug,
    "SmartBulb": iot.IotBulb,
    "SmartLightStrip": iot.IotLightStrip,
    "SmartStrip": iot.IotStrip,
    "SmartDimmer": iot.IotDimmer,
    "SmartBulbPreset": IotLightPreset,
}
deprecated_classes = {
    "SmartDeviceException": KasaException,
    "UnsupportedDeviceException": UnsupportedDeviceError,
    "AuthenticationException": AuthenticationError,
    "TimeoutException": TimeoutError,
    "ConnectionType": DeviceConnectionParameters,
    "EncryptType": DeviceEncryptionType,
    "DeviceFamilyType": DeviceFamily,
}

if not TYPE_CHECKING:

    def __getattr__(name: str) -> Any:
        if name in deprecated_names:
            warn(f"{name} is deprecated", DeprecationWarning, stacklevel=2)
            return globals()[f"_deprecated_{name}"]
        if name in deprecated_smart_devices:
            new_class = deprecated_smart_devices[name]
            package_name = ".".join(new_class.__module__.split(".")[:-1])
            warn(
                f"{name} is deprecated, use {new_class.__name__} from "
                + f"package {package_name} instead or use Discover.discover_single()"
                + " and Device.connect() to support new protocols",
                DeprecationWarning,
                stacklevel=2,
            )
            return new_class
        if name in deprecated_classes:
            new_class = deprecated_classes[name]  # type: ignore[assignment]
            msg = f"{name} is deprecated, use {new_class.__name__} instead"
            warn(msg, DeprecationWarning, stacklevel=2)
            return new_class
        raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


if TYPE_CHECKING:
    SmartDevice = Device
    SmartBulb = iot.IotBulb
    SmartPlug = iot.IotPlug
    SmartLightStrip = iot.IotLightStrip
    SmartStrip = iot.IotStrip
    SmartDimmer = iot.IotDimmer
    SmartBulbPreset = IotLightPreset

    SmartDeviceException = KasaException
    UnsupportedDeviceException = UnsupportedDeviceError
    AuthenticationException = AuthenticationError
    TimeoutException = TimeoutError
    ConnectionType = DeviceConnectionParameters
    EncryptType = DeviceEncryptionType
    DeviceFamilyType = DeviceFamily

    # Instanstiate all classes so the type checkers catch abstract issues
    from . import smart

    smart.SmartDevice("127.0.0.1")
    iot.IotDevice("127.0.0.1")
    iot.IotPlug("127.0.0.1")
    iot.IotBulb("127.0.0.1")
    iot.IotLightStrip("127.0.0.1")
    iot.IotStrip("127.0.0.1")
    iot.IotDimmer("127.0.0.1")