from pathlib import Path
from typing import Generator

import pytest

from hamqtt.config import Config, MqttConfig, load_config, save_config


@pytest.fixture  # type: ignore[misc]
def mock_config_path(tmp_path: Path) -> Generator[Path, None, None]:
    config_dir = tmp_path / ".config" / "hamqtt"
    config_file = config_dir / "config.json"
    legacy_dir = tmp_path / ".config" / "ha-cli"
    legacy_file = legacy_dir / "config.json"

    # Patch the constants in the config module
    with pytest.MonkeyPatch.context() as m:
        m.setattr("hamqtt.config.CONFIG_DIR", config_dir)
        m.setattr("hamqtt.config.CONFIG_FILE", config_file)
        m.setattr("hamqtt.config.LEGACY_CONFIG_DIR", legacy_dir)
        m.setattr("hamqtt.config.LEGACY_CONFIG_FILE", legacy_file)
        yield config_file


def test_load_config_defaults(mock_config_path: Path) -> None:
    """Test loading config when file doesn't exist returns defaults"""
    config = load_config()
    assert config.mqtt.host == "localhost"
    assert config.mqtt.port == 1883
    assert config.mqtt.username is None
    assert config.mqtt.password is None


def test_save_and_load_config(mock_config_path: Path) -> None:
    """Test saving and then loading a configuration"""
    mqtt_config = MqttConfig(host="192.168.1.100", port=1884, username="user", password="password")
    config = Config(mqtt=mqtt_config)

    save_config(config)

    assert mock_config_path.exists()

    loaded_config = load_config()
    assert loaded_config.mqtt.host == "192.168.1.100"
    assert loaded_config.mqtt.port == 1884
    assert loaded_config.mqtt.username == "user"
    assert loaded_config.mqtt.password == "password"


def test_load_config_invalid_json(mock_config_path: Path) -> None:
    """Test loading config with invalid JSON returns defaults"""
    mock_config_path.parent.mkdir(parents=True, exist_ok=True)
    mock_config_path.write_text("{invalid_json")

    config = load_config()
    # Should fallback to default
    assert config.mqtt.host == "localhost"


def test_migration_success(mock_config_path: Path) -> None:
    """Test successful migration from legacy config"""
    config_dir = mock_config_path.parent
    legacy_dir = config_dir.parent / "ha-cli"
    legacy_dir.mkdir(parents=True, exist_ok=True)

    legacy_config = config_dir.parent / "ha-cli" / "config.json"
    legacy_config.write_text('{"mqtt": {"host": "legacy-host", "port": 1234}}')

    # Ensure target dir doesn't exist yet
    if config_dir.exists():
        import shutil

        shutil.rmtree(config_dir)

    config = load_config()

    assert config.mqtt.host == "legacy-host"
    assert config.mqtt.port == 1234

    # Check if directory was renamed/migrated
    assert config_dir.exists()
    assert (config_dir / "config.json").exists()
    assert not legacy_dir.exists()


def test_migration_invalid_legacy(mock_config_path: Path) -> None:
    """Test that invalid legacy config is ignored"""
    config_dir = mock_config_path.parent
    legacy_dir = config_dir.parent / "ha-cli"
    legacy_dir.mkdir(parents=True, exist_ok=True)

    legacy_config = legacy_dir / "config.json"
    legacy_config.write_text('{"invalid": "json"')  # Invalid JSON

    # Ensure target dir doesn't exist
    if config_dir.exists():
        import shutil

        shutil.rmtree(config_dir)

    config = load_config()

    # Should default and NOT migrate
    assert config.mqtt.host == "localhost"
    assert not config_dir.exists()
    assert legacy_dir.exists()
