"""Tests for the configuration pipeline (loader → merger → validator).

IMPORTANT: These tests verify correct behavior across the full pipeline.
The bugs span THREE source files — you need to fix ALL of them.
DO NOT modify these tests.
"""

import pytest
from src.loader import load_config, DEFAULT_CONFIG
from src.merger import merge_configs
from src.validator import validate_config


class TestLoader:
    def test_defaults_applied(self):
        config = load_config({})
        assert config["name"] == "default"
        assert config["priority"] == 5
        assert config["enabled"] is True
        assert config["tags"] == []

    def test_string_priority_converted_to_int(self):
        """Priority should always be int, even if input is string."""
        config = load_config({"priority": "3"})
        assert config["priority"] == 3
        assert isinstance(config["priority"], int)

    def test_int_priority_preserved(self):
        config = load_config({"priority": 7})
        assert config["priority"] == 7
        assert isinstance(config["priority"], int)

    def test_all_fields(self):
        config = load_config({
            "name": "production",
            "priority": 1,
            "enabled": False,
            "tags": ["prod", "critical"],
        })
        assert config["name"] == "production"
        assert config["priority"] == 1
        assert config["enabled"] is False
        assert config["tags"] == ["prod", "critical"]


class TestMerger:
    def test_override_takes_precedence(self):
        base = {"name": "base", "priority": 5, "enabled": True, "tags": []}
        override = {"name": "override", "enabled": False}
        merged = merge_configs(base, override)
        assert merged["name"] == "override"
        assert merged["enabled"] is False

    def test_higher_priority_wins(self):
        """Lower number = higher priority. Override wins if lower."""
        base = {"name": "base", "priority": 5, "tags": []}
        override = {"priority": 2}
        merged = merge_configs(base, override)
        assert merged["priority"] == 2

    def test_lower_priority_kept(self):
        """Base priority kept if it's already higher (lower number)."""
        base = {"name": "base", "priority": 2, "tags": []}
        override = {"priority": 8}
        merged = merge_configs(base, override)
        assert merged["priority"] == 2

    def test_tags_combined(self):
        base = {"name": "b", "priority": 5, "tags": ["a", "b"]}
        override = {"tags": ["b", "c"]}
        merged = merge_configs(base, override)
        assert sorted(merged["tags"]) == ["a", "b", "c"]

    def test_merge_with_int_priorities(self):
        """Merge should work correctly with int priorities."""
        base = {"name": "base", "priority": 5, "tags": []}
        override = {"priority": 3}
        merged = merge_configs(base, override)
        assert merged["priority"] == 3
        assert isinstance(merged["priority"], int)


class TestValidator:
    def test_valid_config(self):
        config = {"name": "test", "priority": 5, "enabled": True, "tags": []}
        result = validate_config(config)
        assert result["valid"] is True
        assert result["errors"] == []

    def test_missing_name(self):
        config = {"name": "", "priority": 5, "enabled": True, "tags": []}
        result = validate_config(config)
        assert result["valid"] is False
        assert any("name" in e for e in result["errors"])

    def test_priority_must_be_int(self):
        """Priority must be validated as integer."""
        config = {"name": "test", "priority": "5", "enabled": True, "tags": []}
        result = validate_config(config)
        assert result["valid"] is False
        assert any("priority" in e for e in result["errors"])

    def test_priority_range_low(self):
        """Priority below 1 is invalid."""
        config = {"name": "test", "priority": 0, "enabled": True, "tags": []}
        result = validate_config(config)
        assert result["valid"] is False
        assert any("priority" in e for e in result["errors"])

    def test_priority_range_high(self):
        """Priority above 10 is invalid."""
        config = {"name": "test", "priority": 11, "enabled": True, "tags": []}
        result = validate_config(config)
        assert result["valid"] is False
        assert any("priority" in e for e in result["errors"])

    def test_valid_priority_range(self):
        """Priority 1-10 is valid."""
        for p in [1, 5, 10]:
            config = {"name": "test", "priority": p, "enabled": True, "tags": []}
            result = validate_config(config)
            assert result["valid"] is True, f"Priority {p} should be valid"


class TestPipelineIntegration:
    """End-to-end tests through the full pipeline."""

    def test_single_config(self):
        raw = {"name": "app", "priority": 3}
        loaded = load_config(raw)
        result = validate_config(loaded)
        assert result["valid"] is True
        assert result["config"]["priority"] == 3

    def test_string_priority_through_pipeline(self):
        """String priority in → int priority out, validated."""
        raw = {"name": "app", "priority": "2", "tags": ["base"]}
        loaded = load_config(raw)
        result = validate_config(loaded)
        assert result["valid"] is True
        assert result["config"]["priority"] == 2
        assert isinstance(result["config"]["priority"], int)

    def test_merge_then_validate(self):
        """Two configs merged and validated."""
        base = load_config({"name": "app", "priority": "5", "tags": ["base"]})
        override = load_config({"priority": 3, "tags": ["override"]})
        merged = merge_configs(base, override)
        result = validate_config(merged)
        assert result["valid"] is True
        assert result["config"]["priority"] == 3
        assert isinstance(result["config"]["priority"], int)

    def test_pipeline_catches_invalid_priority(self):
        """Pipeline should catch priority out of range."""
        loaded = load_config({"name": "bad", "priority": 0})
        result = validate_config(loaded)
        assert result["valid"] is False
        assert any("priority" in e for e in result["errors"])
