# meteo/config.py
from __future__ import annotations

from dataclasses import dataclass
from typing import Self

import os

from dotenv import load_dotenv


@dataclass(frozen=True)
class InfluxSettings:
    """
    Configuration nécessaire pour communiquer avec un serveur InfluxDB 2.x.

    Les valeurs sont généralement chargées depuis des variables d'environnement,
    éventuellement via un fichier `.env` à la racine du projet.
    """

    url: str
    token: str
    org: str
    bucket: str

    @classmethod
    def from_env(cls) -> Self:
        """
        Construit un objet `InfluxSettings` à partir des variables d'environnement.

        Variables attendues :
        - INFLUXDB_URL
        - INFLUXDB_TOKEN
        - INFLUXDB_ORG
        - INFLUXDB_BUCKET

        Lève une RuntimeError si une variable obligatoire est manquante.
        """
        # Charge un éventuel fichier .env (idempotent)
        load_dotenv()

        url = os.getenv("INFLUXDB_URL")
        token = os.getenv("INFLUXDB_TOKEN")
        org = os.getenv("INFLUXDB_ORG")
        bucket = os.getenv("INFLUXDB_BUCKET")

        values = {
            "INFLUXDB_URL": url,
            "INFLUXDB_TOKEN": token,
            "INFLUXDB_ORG": org,
            "INFLUXDB_BUCKET": bucket,
        }

        missing = [name for name, value in values.items() if not value]
        if missing:
            missing_str = ", ".join(missing)
            raise RuntimeError(
                f"Les variables d'environnement suivantes sont manquantes : {missing_str}. "
                "Définissez-les dans votre environnement ou dans un fichier .env."
            )

        return cls(
            url=url,     # type: ignore[arg-type]
            token=token, # type: ignore[arg-type]
            org=org,     # type: ignore[arg-type]
            bucket=bucket,  # type: ignore[arg-type]
        )


@dataclass(frozen=True)
class StationLocation:
    """
    Décrit la position géographique de la station météo.
    Utilisée pour les calculs astronomiques (ex: élévation du soleil).
    """

    latitude: float
    longitude: float
    elevation_m: float = 0.0

    @classmethod
    def from_env(cls, *, optional: bool = False) -> Self | None:
        """
        Charge les coordonnées GPS depuis les variables d'environnement :
        - STATION_LATITUDE (obligatoire)
        - STATION_LONGITUDE (obligatoire)
        - STATION_ELEVATION (optionnelle, en mètres)
        """
        load_dotenv()

        lat = os.getenv("STATION_LATITUDE")
        lon = os.getenv("STATION_LONGITUDE")
        elev = os.getenv("STATION_ELEVATION")

        if not lat or not lon:
            if optional:
                return None
            raise RuntimeError(
                "Les variables STATION_LATITUDE et STATION_LONGITUDE doivent être définies "
                "pour calculer l'élévation solaire."
            )

        latitude = float(lat)
        longitude = float(lon)
        elevation = float(elev) if elev else 0.0

        return cls(latitude=latitude, longitude=longitude, elevation_m=elevation)

    def to_astral_observer_kwargs(self) -> dict[str, float]:
        """
        Prépare les arguments attendus par astral.Observer.
        """
        return {
            "latitude": self.latitude,
            "longitude": self.longitude,
            "elevation": self.elevation_m,
        }
