"""Weather datapoint calculator."""

from __future__ import annotations

from typing import TYPE_CHECKING

import meteocalc

from .sensor import SENSOR_MAP

if TYPE_CHECKING:
    import datetime as dt

_INCHES_2_MM = 25.4
_WATT_METERS_SQUARED_2_LUX = 0.0079
_MPH_2_KMH = 1.60934
_KM_2_MI = 0.6213712
_INHG_2_HPA = 33.86


def convert_fahrenheit_to_celsius(
    data: dict[str, str | int | float | dt.datetime | None],
    key_source: str,
    key_destination: str,
) -> None:
    """Convert f to c."""
    if key_source in data:
        data[key_destination] = round(meteocalc.Temp(data[key_source], "F").c, 1)


def _convert_inches_to_mm(
    data: dict[str, str | int | float | dt.datetime | None],
    key_source: str,
    key_destination: str,
) -> None:
    """Convert source value from inches to mm and save it into destination."""
    if key_source in data:
        data[key_destination] = round(data[key_source] * _INCHES_2_MM, 1)


def weather_datapoints(  # noqa: C901, PLR0912
    data: dict[str, str],
) -> dict[str, str | int | float | dt.datetime | None]:
    """Calculate and convert weather data."""
    for key, value in data.copy().items():
        if key in SENSOR_MAP:
            mapping = SENSOR_MAP[key]
            if value:
                data[key] = mapping.stype.convert_fn(value)
            else:
                data[key] = None

    if "solarradiation" in data:
        data["solarradiation_lux"] = round(
            data["solarradiation"] / _WATT_METERS_SQUARED_2_LUX, 1
        )

    # lightning
    if value := data.get("lightning"):
        data["lightning_mi"] = round(value * _KM_2_MI)

    for source, dst in (
        ("tempf", "tempc"),
        ("tempinf", "tempinc"),
        ("tf_co2", "tf_co2c"),
        ("temp1f", "temp1c"),
        ("temp2f", "temp2c"),
        ("temp3f", "temp3c"),
        ("temp4f", "temp4c"),
        ("temp5f", "temp5c"),
        ("temp6f", "temp6c"),
        ("temp7f", "temp7c"),
        ("temp8f", "temp8c"),
        ("tf_ch1", "tf_ch1c"),
        ("tf_ch2", "tf_ch2c"),
        ("tf_ch3", "tf_ch3c"),
        ("tf_ch4", "tf_ch4c"),
        ("tf_ch5", "tf_ch5c"),
        ("tf_ch6", "tf_ch6c"),
        ("tf_ch7", "tf_ch7c"),
        ("tf_ch8", "tf_ch8c"),
    ):
        convert_fahrenheit_to_celsius(data, source, dst)

    # speeds
    for source, dst in (
        ("windspeedmph", "windspeedkmh"),
        ("windgustmph", "windgustkmh"),
        ("maxdailygust", "maxdailygustkmh"),
        ("windspdmph_avg10m", "windspdkmh_avg10m"),
    ):
        if source in data:
            data[dst] = round(data[source] * _MPH_2_KMH, 1)

    for key in (
        "eventrain",
        "hourlyrain",
        "dailyrain",
        "weeklyrain",
        "monthlyrain",
        "yearlyrain",
        "totalrain",
        "rainrate",
        "last24hrain",
    ):
        _convert_inches_to_mm(data, f"{key}in", f"{key}mm")

    for key in (
        "erain_piezo",
        "hrain_piezo",
        "drain_piezo",
        "wrain_piezo",
        "mrain_piezo",
        "yrain_piezo",
        "rrain_piezo",
        "last24hrain_piezo",
    ):
        _convert_inches_to_mm(data, key, f"{key}mm")

    # Pressure
    for key in ("baromrel", "baromabs"):
        if value := data.get(f"{key}in"):
            data[f"{key}hpa"] = round(value * _INHG_2_HPA, 1)

    # Wind chill
    if "tempf" in data and "windspeedmph" in data:
        try:
            wind_chill = meteocalc.wind_chill(data["tempf"], data["windspeedmph"])
        except ValueError:
            data["windchillf"] = None
            data["windchillc"] = None
        else:
            data["windchillf"] = round(wind_chill.f, 1)
            data["windchillc"] = round(wind_chill.c, 1)

    # Dew point
    for j in ["", "in", "1", "2", "3", "4", "5", "6", "7", "8"]:
        if f"temp{j}c" in data and f"humidity{j}" in data:
            dewpoint = meteocalc.dew_point(data[f"temp{j}c"], data[f"humidity{j}"])
            data[f"dewpoint{j}c"] = round(dewpoint.c, 1)
            data[f"dewpoint{j}f"] = round(dewpoint.f, 1)

    # Feels like
    if "tempf" in data and "humidity" in data and "windspeedmph" in data:
        feels_like = meteocalc.feels_like(
            data["tempf"], data["humidity"], data["windspeedmph"]
        )
        data["tempfeelsf"] = round(feels_like.f, 1)
        data["tempfeelsc"] = round(feels_like.c, 1)

    return data
