from pathlib import Path

import pytest
import yaml

from gallery.config import ConfigManager, GalleryConfig, GalleryDefaults, GallerySource


def test_gallery_source_path_conversion():
    source = GallerySource(name="test", path="/test/path")
    assert source.name == "test"
    assert source.path == Path("/test/path")


def test_gallery_defaults():
    defaults = GalleryDefaults()
    assert defaults.png_dpi == 400
    assert defaults.plot_root == "gallery"
    assert defaults.cache_enabled is True
    assert defaults.inherit_from_parent is True


def test_gallery_config_defaults():
    cfg = GalleryConfig(web_folder="/web")
    assert cfg.web_folder == Path("/web")
    assert cfg.sources == []
    assert cfg.png_dpi == GalleryDefaults.png_dpi
    assert cfg.plot_root == GalleryDefaults.plot_root
    assert cfg.cache_enabled == GalleryDefaults.cache_enabled
    assert cfg.inherit_from_parent == GalleryDefaults.inherit_from_parent


def test_gallery_config_sources_from_dicts():
    cfg = GalleryConfig(web_folder="/web", sources=[{"name": "s1", "path": "/p1"}])
    assert len(cfg.sources) == 1
    assert isinstance(cfg.sources[0], GallerySource)
    assert cfg.sources[0].name == "s1"
    assert cfg.sources[0].path == Path("/p1")


def test_gallery_config_sources_invalid_type():
    with pytest.raises(TypeError):
        GalleryConfig(web_folder="/web", sources=[123])


def test_gallery_config_from_yaml(tmp_path):
    yaml_content = {
        "paths": {"web_folder": "/test/web"},
        "gallery": {"plot_root": "test_plots", "png_dpi": 200},
        "metadata": {"cache_enabled": False, "inherit_from_parent": False},
        "sources": [
            {"name": "source1", "path": "/path1"},
            {"name": "source2", "path": "/path2"},
        ],
    }

    yaml_file = tmp_path / "test_config.yaml"
    with yaml_file.open("w") as f:
        yaml.dump(yaml_content, f)

    cfg = GalleryConfig.from_yaml(yaml_file)

    assert cfg.web_folder == Path("/test/web")
    assert cfg.plot_root == "test_plots"
    assert cfg.png_dpi == 200
    assert cfg.cache_enabled is False
    assert cfg.inherit_from_parent is False
    assert len(cfg.sources) == 2
    assert cfg.sources[0].name == "source1"
    assert cfg.sources[0].path == Path("/path1")


def test_gallery_config_from_yaml_missing_file():
    with pytest.raises(FileNotFoundError):
        GalleryConfig.from_yaml("/nonexistent/file.yaml")


def test_gallery_config_from_yaml_missing_web_folder(tmp_path):
    yaml_file = tmp_path / "no_web_folder.yaml"
    yaml_file.write_text(yaml.dump({"gallery": {"plot_root": "plots"}}))

    with pytest.raises(ValueError):
        GalleryConfig.from_yaml(yaml_file)


def test_gallery_config_from_yaml_partial_data(tmp_path):
    yaml_content = {"paths": {"web_folder": "/min_web"}}

    yaml_file = tmp_path / "minimal_config.yaml"
    yaml_file.write_text(yaml.dump(yaml_content))

    cfg = GalleryConfig.from_yaml(yaml_file)

    assert cfg.web_folder == Path("/min_web")
    assert cfg.png_dpi == GalleryDefaults.png_dpi
    assert cfg.plot_root == GalleryDefaults.plot_root
    assert cfg.cache_enabled is True
    assert cfg.sources == []


def test_gallery_config_to_yaml_round_trip(tmp_path):
    cfg = GalleryConfig(
        web_folder="/web",
        sources=[{"name": "test", "path": "/test"}],
        plot_root="plots",
        png_dpi=300,
    )

    yaml_file = tmp_path / "output_config.yaml"
    cfg.to_yaml(yaml_file)

    assert yaml_file.exists()

    reloaded = GalleryConfig.from_yaml(yaml_file)
    assert reloaded.web_folder == cfg.web_folder
    assert reloaded.plot_root == cfg.plot_root
    assert reloaded.png_dpi == cfg.png_dpi
    assert reloaded.sources[0].name == "test"


# ---------------------------------------------------------------------------
# ConfigManager
# ---------------------------------------------------------------------------


@pytest.fixture
def config_manager(tmp_path):
    path = tmp_path / "config.yaml"
    path.write_text(
        yaml.dump(
            {
                "paths": {"web_folder": "/web"},
                "gallery": {"plot_root": "gallery", "png_dpi": 400},
                "sources": [{"name": "existing", "path": "/existing"}],
            }
        )
    )
    return ConfigManager(path)


def test_config_manager_get(config_manager):
    assert config_manager.get("gallery.png_dpi") == 400


def test_config_manager_get_missing_key(config_manager):
    with pytest.raises(KeyError):
        config_manager.get("gallery.nonexistent")


def test_config_manager_set(config_manager):
    config_manager.set("gallery.png_dpi", "600")
    assert config_manager.get("gallery.png_dpi") == 600


def test_config_manager_list_all(config_manager):
    data = config_manager.list_all()
    assert data["paths"]["web_folder"] == "/web"


def test_config_manager_add_source(config_manager):
    config_manager.add_source("new_source", "/new/path")
    sources = config_manager.list_sources()
    assert {"name": "new_source", "path": "/new/path"} in sources


def test_config_manager_add_source_duplicate(config_manager):
    with pytest.raises(ValueError):
        config_manager.add_source("existing", "/other/path")


def test_config_manager_remove_source(config_manager):
    config_manager.remove_source("existing")
    assert config_manager.list_sources() == []


def test_config_manager_remove_source_not_found(config_manager):
    with pytest.raises(KeyError):
        config_manager.remove_source("nonexistent")


def test_config_manager_list_sources(config_manager):
    sources = config_manager.list_sources()
    assert sources == [{"name": "existing", "path": "/existing"}]
