import datetime
from enum import StrEnum, auto
from typing import Self

from pydantic import BaseModel


class Model(BaseModel):
    class Config:
        use_enum_values = True


class Location(Model):
    id: str
    name: str
    provider: str
    lat: float
    lon: float
    country: str
    country_code: str
    district: str
    subdistrict: str


class Cloudness(StrEnum):
    CLEAR = auto()
    PARTLY_CLOUDY = auto()
    CLOUDY = auto()
    MAINLY_CLOUDY = auto()


class Precipitation(StrEnum):
    NO = auto()
    SMALL_RAIN = auto()
    RAIN = auto()
    HEAVY_RAIN = auto()
    SHOWER = auto()
    SNOW = auto()
    HEAVY_SNOW = auto()
    HAIL = auto()


class Sky(Model):
    cloudness: Cloudness
    precipitation: Precipitation
    thunder: bool
    fog: bool


class WindDirection(StrEnum):
    CALM = auto()
    N = auto()
    NE = auto()
    E = auto()
    SE = auto()
    S = auto()
    SW = auto()
    W = auto()
    NW = auto()


class WindDirectionDeg(float):
    @property
    def direction(self) -> WindDirection:
        return self.to_direction()

    @property
    def value(self) -> float:
        return self

    # pylint:disable=too-many-return-statements
    def to_direction(self) -> WindDirection:
        if self == -1:
            return WindDirection.CALM
        elif self > 337.5 or self <= 22.25:
            return WindDirection.N
        elif self <= 67.5:
            return WindDirection.NE
        elif self <= 112.5:
            return WindDirection.E
        elif self <= 157.5:
            return WindDirection.SE
        elif self <= 202.5:
            return WindDirection.S
        elif self <= 247.5:
            return WindDirection.SW
        elif self <= 292.5:
            return WindDirection.W
        elif self <= 337.5:
            return WindDirection.NW
        else:
            raise ValueError(self)

    @classmethod
    def from_direction(cls, direction: WindDirection) -> Self:
        return cls(
            {
                WindDirection.CALM: -1,
                WindDirection.N: 0,
                WindDirection.NE: 45,
                WindDirection.E: 90,
                WindDirection.SE: 135,
                WindDirection.S: 180,
                WindDirection.SW: 225,
                WindDirection.W: 270,
                WindDirection.NW: 315,
            }[direction]
        )


class WeatherValue(Model):
    date: datetime.datetime
    sky: Sky
    temperature: list[int]
    wind_speed: int
    wind_gust: int
    wind_direction: float
    precipitation: float
    pressure: list[int]
    humidity: int


class WeatherResponse(Model):
    location: str
    date: datetime.date
    period: str
    values: list[WeatherValue]
