"""The ElevenLabs text-to-speech integration."""

from dataclasses import dataclass
import logging

from elevenlabs import AsyncElevenLabs, Model
from elevenlabs.core import ApiError
from httpx import ConnectError

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY, CONF_MODEL, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import (
    ConfigEntryAuthFailed,
    ConfigEntryError,
    ConfigEntryNotReady,
)
from homeassistant.helpers.httpx_client import get_async_client

from .const import CONF_STT_MODEL

_LOGGER = logging.getLogger(__name__)

PLATFORMS: list[Platform] = [
    Platform.STT,
    Platform.TTS,
]


async def get_model_by_id(client: AsyncElevenLabs, model_id: str) -> Model | None:
    """Get ElevenLabs model from their API by the model_id."""
    models = await client.models.list()

    for maybe_model in models:
        if maybe_model.model_id == model_id:
            return maybe_model
    return None


@dataclass(kw_only=True, slots=True)
class ElevenLabsData:
    """ElevenLabs data type."""

    client: AsyncElevenLabs
    model: Model
    stt_model: str


type ElevenLabsConfigEntry = ConfigEntry[ElevenLabsData]


async def async_setup_entry(hass: HomeAssistant, entry: ElevenLabsConfigEntry) -> bool:
    """Set up ElevenLabs text-to-speech from a config entry."""
    entry.add_update_listener(update_listener)
    httpx_client = get_async_client(hass)
    client = AsyncElevenLabs(
        api_key=entry.data[CONF_API_KEY], httpx_client=httpx_client
    )
    model_id = entry.options[CONF_MODEL]
    try:
        model = await get_model_by_id(client, model_id)
    except ConnectError as err:
        raise ConfigEntryNotReady("Failed to connect") from err
    except ApiError as err:
        raise ConfigEntryAuthFailed("Auth failed") from err

    if model is None or (not model.languages):
        raise ConfigEntryError("Model could not be resolved")

    entry.runtime_data = ElevenLabsData(
        client=client, model=model, stt_model=entry.options[CONF_STT_MODEL]
    )
    await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

    return True


async def async_unload_entry(hass: HomeAssistant, entry: ElevenLabsConfigEntry) -> bool:
    """Unload a config entry."""
    return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)


async def update_listener(
    hass: HomeAssistant, config_entry: ElevenLabsConfigEntry
) -> None:
    """Handle options update."""
    await hass.config_entries.async_reload(config_entry.entry_id)


async def async_migrate_entry(
    hass: HomeAssistant, config_entry: ElevenLabsConfigEntry
) -> bool:
    """Migrate old config entry to new format."""

    _LOGGER.debug(
        "Migrating configuration from version %s.%s",
        config_entry.version,
        config_entry.minor_version,
    )

    if config_entry.version == 1:
        new_options = {**config_entry.options}

        if config_entry.minor_version < 2:
            # Add defaults only if they're not already present
            if "stt_auto_language" not in new_options:
                new_options["stt_auto_language"] = False
            if "stt_model" not in new_options:
                new_options["stt_model"] = "scribe_v1"

        hass.config_entries.async_update_entry(
            config_entry,
            options=new_options,
            minor_version=2,
            version=1,
        )

    _LOGGER.debug(
        "Migration to configuration version %s.%s successful",
        config_entry.version,
        config_entry.minor_version,
    )

    return True  # already up to date
