# test_config.py
"""Tests for configuration file loader module."""

import os
import tempfile
from pathlib import Path

import pytest
import yaml

from earthcatalog.config import load_config, merge_cli_overrides, save_config


class TestLoadConfig:
    """Tests for load_config function."""

    def test_load_explicit_path(self):
        """Test loading config from explicit path."""
        with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
            yaml.dump({"grid_resolution": 5, "batch_threshold": 5000}, f)
            temp_path = f.name

        try:
            config = load_config(temp_path)
            assert config["grid_resolution"] == 5
            assert config["batch_threshold"] == 5000
        finally:
            os.unlink(temp_path)

    def test_load_missing_explicit_path_raises(self):
        """Test that missing explicit path raises FileNotFoundError."""
        with pytest.raises(FileNotFoundError):
            load_config("/nonexistent/path/config.yaml")

    def test_load_default_path_if_exists(self, tmp_path, monkeypatch):
        """Test loading from ./earthcatalog.yaml if it exists."""
        config_content = {"grid_system": "s2", "concurrent_requests": 100}

        # Create config file in temp directory
        config_file = tmp_path / "earthcatalog.yaml"
        with open(config_file, "w") as f:
            yaml.dump(config_content, f)

        # Change to temp directory
        monkeypatch.chdir(tmp_path)

        config = load_config()
        assert config["grid_system"] == "s2"
        assert config["concurrent_requests"] == 100

    def test_load_returns_empty_when_no_config(self, tmp_path, monkeypatch):
        """Test that empty dict is returned when no config file exists."""
        # Change to empty temp directory
        monkeypatch.chdir(tmp_path)

        config = load_config()
        assert config == {}

    def test_load_empty_yaml_file(self):
        """Test loading an empty YAML file returns empty dict."""
        with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
            f.write("")  # Empty file
            temp_path = f.name

        try:
            config = load_config(temp_path)
            assert config == {}
        finally:
            os.unlink(temp_path)

    def test_load_invalid_yaml_raises(self):
        """Test that invalid YAML raises an error."""
        with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
            f.write("invalid: yaml: content: [")
            temp_path = f.name

        try:
            with pytest.raises(yaml.YAMLError):
                load_config(temp_path)
        finally:
            os.unlink(temp_path)

    def test_load_non_mapping_yaml_raises(self):
        """Test that non-mapping YAML content raises ValueError."""
        with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
            f.write("- item1\n- item2\n")  # List instead of mapping
            temp_path = f.name

        try:
            with pytest.raises(ValueError, match="YAML mapping"):
                load_config(temp_path)
        finally:
            os.unlink(temp_path)


class TestMergeCliOverrides:
    """Tests for merge_cli_overrides function."""

    def test_cli_overrides_config(self):
        """Test that CLI args override config file values."""
        file_config = {"grid_resolution": 2, "batch_threshold": 10000}
        cli_args = {"grid_resolution": 5}  # Override

        result = merge_cli_overrides(file_config, cli_args)

        assert result["grid_resolution"] == 5  # Overridden
        assert result["batch_threshold"] == 10000  # Preserved

    def test_none_cli_args_ignored(self):
        """Test that None CLI args don't override config values."""
        file_config = {"grid_resolution": 2, "batch_threshold": 10000}
        cli_args = {"grid_resolution": None, "batch_threshold": None}

        result = merge_cli_overrides(file_config, cli_args)

        # Original values preserved because CLI args are None
        assert result["grid_resolution"] == 2
        assert result["batch_threshold"] == 10000

    def test_cli_adds_new_keys(self):
        """Test that CLI can add keys not in config file."""
        file_config = {"grid_resolution": 2}
        cli_args = {"distributed": True, "stac_hook": "module:pkg:func"}

        result = merge_cli_overrides(file_config, cli_args)

        assert result["grid_resolution"] == 2
        assert result["distributed"] is True
        assert result["stac_hook"] == "module:pkg:func"

    def test_empty_config_uses_cli(self):
        """Test that empty config uses all CLI values."""
        file_config = {}
        cli_args = {
            "input_file": "data.parquet",
            "grid_resolution": 5,
            "batch_threshold": 5000,
        }

        result = merge_cli_overrides(file_config, cli_args)

        assert result["input_file"] == "data.parquet"
        assert result["grid_resolution"] == 5
        assert result["batch_threshold"] == 5000


class TestSaveConfig:
    """Tests for save_config function."""

    def test_save_config_creates_file(self):
        """Test that save_config creates a YAML file."""
        config = {"grid_resolution": 5, "batch_threshold": 7500}

        with tempfile.TemporaryDirectory() as tmp_dir:
            config_path = Path(tmp_dir) / "test_config.yaml"
            save_config(config, config_path)

            assert config_path.exists()

            # Verify content
            with open(config_path) as f:
                loaded = yaml.safe_load(f)

            assert loaded["grid_resolution"] == 5
            assert loaded["batch_threshold"] == 7500

    def test_save_config_overwrites_existing(self):
        """Test that save_config overwrites existing file."""
        original = {"value": "original"}
        updated = {"value": "updated"}

        with tempfile.TemporaryDirectory() as tmp_dir:
            config_path = Path(tmp_dir) / "config.yaml"

            # Save original
            save_config(original, config_path)

            # Overwrite with updated
            save_config(updated, config_path)

            with open(config_path) as f:
                loaded = yaml.safe_load(f)

            assert loaded["value"] == "updated"


class TestConfigIntegration:
    """Integration tests for config loading with ProcessingConfig."""

    def test_full_config_workflow(self):
        """Test complete workflow: load config, merge CLI, create ProcessingConfig."""
        from earthcatalog.ingestion_pipeline import ProcessingConfig

        # Create a config file
        file_config = {
            "grid_resolution": 4,
            "batch_threshold": 8000,
            "concurrent_requests": 75,
        }

        with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
            yaml.dump(file_config, f)
            config_path = f.name

        # Create a dummy input file
        with tempfile.NamedTemporaryFile(suffix=".parquet", delete=False) as pq:
            import pandas as pd

            pd.DataFrame({"url": ["url1"]}).to_parquet(pq.name)
            input_path = pq.name

        try:
            # Load config file
            loaded = load_config(config_path)

            # Simulate CLI args (some override, some None)
            cli_args = {
                "input_file": input_path,
                "output_catalog": "/tmp/catalog",
                "scratch_location": "/tmp/scratch",
                "grid_resolution": None,  # Use config value
                "batch_threshold": 5000,  # Override
            }

            # Merge
            merged = merge_cli_overrides(loaded, cli_args)

            # Create ProcessingConfig
            config = ProcessingConfig(
                input_file=merged["input_file"],
                output_catalog=merged["output_catalog"],
                scratch_location=merged["scratch_location"],
                grid_resolution=merged.get("grid_resolution", 2),
                batch_threshold=merged.get("batch_threshold", 10000),
                concurrent_requests=merged.get("concurrent_requests", 50),
            )

            # Verify merged values
            assert config.grid_resolution == 4  # From file
            assert config.batch_threshold == 5000  # From CLI (override)
            assert config.concurrent_requests == 75  # From file

        finally:
            os.unlink(config_path)
            os.unlink(input_path)
