from typing import Optional

from pydantic import Field, computed_field, field_validator

from akkudoktoreos.config.configabc import SettingsBaseModel
from akkudoktoreos.core.coreabc import get_prediction
from akkudoktoreos.prediction.elecpriceabc import ElecPriceProvider
from akkudoktoreos.prediction.elecpriceakkudoktor import (
    ElecPriceAkkudoktorCommonSettings,
)
from akkudoktoreos.prediction.elecpriceenergycharts import (
    ElecPriceEnergyChartsCommonSettings,
)
from akkudoktoreos.prediction.elecpricefixed import ElecPriceFixedCommonSettings
from akkudoktoreos.prediction.elecpriceimport import ElecPriceImportCommonSettings
from akkudoktoreos.prediction.elecpricesmard import ElecPriceSMARDCommonSettings
from akkudoktoreos.prediction.elecpricetibber import ElecPriceTibberCommonSettings


def elecprice_provider_ids() -> list[str]:
    """Valid elecprice provider ids."""
    try:
        prediction_eos = get_prediction()
    except Exception:
        # Prediction may not be initialized. Return static built-in provider ids.
        return [
            "ElecPriceAkkudoktor",
            "ElecPriceEnergyCharts",
            "ElecPriceFixed",
            "ElecPriceSMARD",
            "ElecPriceImport",
            "ElecPriceTibber",
        ]

    return [
        provider.provider_id()
        for provider in prediction_eos.providers
        if isinstance(provider, ElecPriceProvider)
    ]


class ElecPriceCommonSettings(SettingsBaseModel):
    """Electricity Price Prediction Configuration."""

    provider: Optional[str] = Field(
        default=None,
        json_schema_extra={
            "description": "Electricity price provider id of provider to be used.",
            "examples": ["ElecPriceAkkudoktor"],
        },
    )

    akkudoktor: ElecPriceAkkudoktorCommonSettings = Field(
        default_factory=ElecPriceAkkudoktorCommonSettings,
        json_schema_extra={"description": "Akkudoktor electricity price provider settings."},
    )

    elecpricefixed: ElecPriceFixedCommonSettings = Field(
        default_factory=ElecPriceFixedCommonSettings,
        json_schema_extra={"description": "Fixed electricity price provider settings."},
    )

    elecpriceimport: ElecPriceImportCommonSettings = Field(
        default_factory=ElecPriceImportCommonSettings,
        json_schema_extra={"description": "Electricity price import provider settings."},
    )

    energycharts: ElecPriceEnergyChartsCommonSettings = Field(
        default_factory=ElecPriceEnergyChartsCommonSettings,
        json_schema_extra={"description": "Energy Charts provider settings."},
    )

    smard: ElecPriceSMARDCommonSettings = Field(
        default_factory=ElecPriceSMARDCommonSettings,
        json_schema_extra={"description": "SMARD electricity price provider settings."},
    )

    tibber: ElecPriceTibberCommonSettings = Field(
        default_factory=ElecPriceTibberCommonSettings,
        json_schema_extra={"description": "Tibber electricity price provider settings."},
    )

    @computed_field  # type: ignore[prop-decorator]
    @property
    def providers(self) -> list[str]:
        """Available electricity price provider ids."""
        return elecprice_provider_ids()

    # Validators
    @field_validator("provider", mode="after")
    @classmethod
    def validate_provider(cls, value: Optional[str]) -> Optional[str]:
        if value is None or value in elecprice_provider_ids():
            return value
        raise ValueError(
            f"Provider '{value}' is not a valid electricity price provider: {elecprice_provider_ids()}."
        )
