"""Provides models that represent the data structures returned by the Roth API.

These are mostly auto-generated using responses received from the API, with some
tweaks to types and names.
"""

from typing import Any, Dict, List, Literal, Optional, Union

from pydantic import BaseModel, Field


class ZoneFlagsModel(BaseModel):
    relay_state: str = Field(..., alias="relayState")
    min_one_window_open: bool = Field(..., alias="minOneWindowOpen")
    algorithm: Literal["heating", "cooling"]
    floor_sensor: int = Field(..., alias="floorSensor")
    humidity_algorytm: int = Field(..., alias="humidityAlgorytm")
    zone_excluded: int = Field(..., alias="zoneExcluded")


class ZoneAttributesModel(BaseModel):
    id: int
    parent_id: int = Field(..., alias="parentId")
    time: str
    during_change: bool = Field(..., alias="duringChange")
    index: int
    current_temperature: Optional[int] = Field(..., alias="currentTemperature")
    set_temperature: int = Field(..., alias="setTemperature")
    flags: ZoneFlagsModel
    zone_state: Literal[
        "zoneOff", "noAlarm", "zoneUnregistered", "sensorDamaged", "noCommunication"
    ] = Field(..., alias="zoneState")
    signal_strength: Optional[int] = Field(..., alias="signalStrength")
    battery_level: Optional[int] = Field(..., alias="batteryLevel")
    actuators_open: int = Field(..., alias="actuatorsOpen")
    humidity: int
    visibility: bool


class ZoneDescriptionModel(BaseModel):
    id: int
    parent_id: int = Field(..., alias="parentId")
    name: str
    style_id: int = Field(..., alias="styleId")
    style_icon: str = Field(..., alias="styleIcon")
    during_change: bool = Field(..., alias="duringChange")


class ZoneModeModel(BaseModel):
    id: int
    parent_id: int = Field(..., alias="parentId")
    mode: Literal["constantTemp", "globalSchedule", "localSchedule", "timeLimit"]
    const_temp_time: int = Field(..., alias="constTempTime")
    set_temperature: int = Field(..., alias="setTemperature")
    schedule_index: int = Field(..., alias="scheduleIndex")


class ScheduleIntervalModel(BaseModel):
    start: int
    stop: int
    temp: int


class LocalScheduleModel(BaseModel):
    id: int
    parent_id: int = Field(..., alias="parentId")
    index: int
    p0_days: List[str] = Field(..., alias="p0Days")
    p0_intervals: List[ScheduleIntervalModel] = Field(..., alias="p0Intervals")
    p0_setback_temp: int = Field(..., alias="p0SetbackTemp")
    p1_days: List[str] = Field(..., alias="p1Days")
    p1_intervals: List[ScheduleIntervalModel] = Field(..., alias="p1Intervals")
    p1_setback_temp: int = Field(..., alias="p1SetbackTemp")


class ZoneModel(BaseModel):
    zone: ZoneAttributesModel
    description: ZoneDescriptionModel
    mode: ZoneModeModel
    schedule: LocalScheduleModel
    actuators: List
    underfloor: Dict[str, Any]
    windows_sensors: List = Field(..., alias="windowsSensors")
    additional_contacts: List = Field(..., alias="additionalContacts")


class GlobalScheduleModel(BaseModel):
    id: int
    parent_id: int = Field(..., alias="parentId")
    index: int
    name: str
    p0_days: List[str] = Field(..., alias="p0Days")
    p0_setback_temp: int = Field(..., alias="p0SetbackTemp")
    p0_intervals: List[ScheduleIntervalModel] = Field(..., alias="p0Intervals")
    p1_days: List[str] = Field(..., alias="p1Days")
    p1_setback_temp: int = Field(..., alias="p1SetbackTemp")
    p1_intervals: List[ScheduleIntervalModel] = Field(..., alias="p1Intervals")


class GlobalSchedulesModel(BaseModel):
    time: str
    during_change: bool = Field(..., alias="duringChange")
    elements: List[GlobalScheduleModel]


class ControllerModeModel(BaseModel):
    id: int
    parent_id: int = Field(..., alias="parentId")
    type: int
    txt_id: int = Field(..., alias="txtId")
    icon_id: int = Field(..., alias="iconId")
    value: int
    menu_id: int = Field(..., alias="menuId")


class ControllerParametersModel(BaseModel):
    controller_mode: ControllerModeModel = Field(..., alias="controllerMode")
    global_schedules_number: Dict[str, Any] = Field(..., alias="globalSchedulesNumber")


class ZonesModel(BaseModel):
    transaction_time: str
    elements: List[ZoneModel]
    global_schedules: GlobalSchedulesModel = Field(..., alias="globalSchedules")
    controller_parameters: ControllerParametersModel = Field(..., alias="controllerParameters")


class ParamsModel(BaseModel):
    description: Optional[str] = None
    working_status: Optional[bool] = Field(None, alias="workingStatus")
    txt_id: Optional[int] = Field(None, alias="txtId")
    icon_id: Optional[int] = Field(None, alias="iconId")
    version: Optional[str] = None
    company_id: Optional[int] = Field(None, alias="companyId")
    controller_name: Optional[str] = Field(None, alias="controllerName")
    main_controller_id: Optional[int] = Field(None, alias="mainControllerId")


class TileModel(BaseModel):
    id: int
    parent_id: int = Field(..., alias="parentId")
    type: Union[int, str]
    menu_id: Optional[int] = Field(None, alias="menuId")
    order_id: Optional[Any] = Field(None, alias="orderId")
    visibility: bool
    params: Optional[ParamsModel] = None


class ModuleModel(BaseModel):
    zones: ZonesModel
    tiles: Optional[List[TileModel]] = []
    tiles_order: Optional[Any] = Field(None, alias="tilesOrder")
    tiles_last_update: Optional[str] = Field(None, alias="tilesLastUpdate")


class AccountModuleModel(BaseModel):
    id: int
    default: bool
    name: str
    email: str
    type: str
    controller_status: Optional[str] = Field(None, alias="controllerStatus")
    module_status: Optional[str] = Field(None, alias="moduleStatus")
    additional_information: Optional[str] = Field(None, alias="additionalInformation")
    phone_number: Optional[Any] = Field(None, alias="phoneNumber")
    zip_code: Optional[str] = Field(None, alias="zipCode")
    tag: Optional[str] = None
    country: Optional[str] = None
    gmt_id: Optional[int] = Field(None, alias="gmtId")
    gmt_time: Optional[str] = Field(None, alias="gmtTime")
    postcode_policy_accepted: Optional[bool] = Field(None, alias="postcodePolicyAccepted")
    style: Optional[str] = None
    version: Optional[str] = None
    company: Optional[str] = None
    udid: str
