import json
from pathlib import Path
from typing import Optional

from pydantic import BaseModel

CONFIG_DIR = Path.home() / ".config" / "hamqtt"
CONFIG_FILE = CONFIG_DIR / "config.json"

LEGACY_CONFIG_DIR = Path.home() / ".config" / "ha-cli"
LEGACY_CONFIG_FILE = LEGACY_CONFIG_DIR / "config.json"


class MqttConfig(BaseModel):
    """
    Configuration for the MQTT connection.

    Attributes:
        host (str): The hostname or IP address of the MQTT broker.
        port (int): The port number of the MQTT broker. Defaults to 1883.
        username (Optional[str]): The username for authentication. Defaults to None.
        password (Optional[str]): The password for authentication. Defaults to None.
        discovery_prefix (str): The prefix used for Home Assistant discovery topics. Defaults to "homeassistant".
    """

    host: str
    port: int = 1883
    username: Optional[str] = None
    password: Optional[str] = None
    discovery_prefix: str = "homeassistant"


class Config(BaseModel):
    """
    Global application configuration.

    Attributes:
        mqtt (MqttConfig): The MQTT connection configuration.
    """

    mqtt: MqttConfig


def _migrate_config() -> None:
    """
    Migrate configuration from legacy directory if it exists and is valid.
    """
    if CONFIG_DIR.exists():
        return

    if not LEGACY_CONFIG_DIR.exists() or not LEGACY_CONFIG_FILE.exists():
        return

    try:
        # Validate that it looks like our config
        data = json.loads(LEGACY_CONFIG_FILE.read_text())
        Config(**data)  # Validate against schema

        # Perform migration
        print(f"Migrating legacy configuration from {LEGACY_CONFIG_DIR} to {CONFIG_DIR}...")
        LEGACY_CONFIG_DIR.rename(CONFIG_DIR)
    except Exception:
        # If it's not a valid config or rename fails, ignore it
        # This prevents taking over a directory that might belong to another tool
        pass


def load_config() -> Config:
    """
    Load the application configuration from the config file.

    If the configuration file does not exist, it attempts to migrate from the legacy location.
    If migration is not possible or file doesn't exist, a default configuration is returned
    with 'localhost' as the MQTT host.

    Returns:
        Config: The loaded or default configuration.
    """
    _migrate_config()

    if not CONFIG_FILE.exists():
        # Return default config if file doesn't exist
        return Config(mqtt=MqttConfig(host="localhost"))

    try:
        data = json.loads(CONFIG_FILE.read_text())
        return Config(**data)
    except Exception as e:
        # Fallback or error handling
        print(f"Error loading config: {e}")
        return Config(mqtt=MqttConfig(host="localhost"))


def save_config(config: Config) -> None:
    """
    Save the application configuration to the config file.

    Creates the configuration directory if it does not exist.

    Args:
        config (Config): The configuration object to save.
    """

    CONFIG_DIR.mkdir(parents=True, exist_ok=True)
    CONFIG_FILE.write_text(config.model_dump_json(indent=2))


def delete_config() -> None:
    """
    Delete the configuration file.
    """
    if CONFIG_FILE.exists():
        CONFIG_FILE.unlink()
