"""Tests for the configuration system."""

from pathlib import Path

import pytest
import yaml

from redhat_oracle.core.config import (
    OracleConfig,
    _apply_env_vars,
    _deep_merge,
    load_config,
)


class TestDeepMerge:
    def test_simple_merge(self) -> None:
        base = {"a": 1, "b": 2}
        override = {"b": 3, "c": 4}
        result = _deep_merge(base, override)
        assert result == {"a": 1, "b": 3, "c": 4}

    def test_nested_merge(self) -> None:
        base = {"sources": {"github": {"token": "old", "use_ssh": True}}}
        override = {"sources": {"github": {"token": "new"}}}
        result = _deep_merge(base, override)
        assert result["sources"]["github"]["token"] == "new"
        assert result["sources"]["github"]["use_ssh"] is True

    def test_override_replaces_non_dict(self) -> None:
        base = {"key": "string_value"}
        override = {"key": {"nested": True}}
        result = _deep_merge(base, override)
        assert result["key"] == {"nested": True}

    def test_base_not_mutated(self) -> None:
        base = {"a": 1}
        override = {"a": 2}
        _deep_merge(base, override)
        assert base["a"] == 1


class TestEnvVarFallback:
    def test_github_token_from_env(self, monkeypatch: pytest.MonkeyPatch) -> None:
        monkeypatch.setenv("ORACLE_GITHUB_TOKEN", "ghp_test123")
        data: dict = {"sources": {"github": {"token": None}}}
        result = _apply_env_vars(data)
        assert result["sources"]["github"]["token"] == "ghp_test123"

    def test_gitlab_token_from_env(self, monkeypatch: pytest.MonkeyPatch) -> None:
        monkeypatch.setenv("ORACLE_GITLAB_TOKEN", "glpat-test456")
        data: dict = {"sources": {"gitlab": {"token": None}}}
        result = _apply_env_vars(data)
        assert result["sources"]["gitlab"]["token"] == "glpat-test456"

    def test_slack_token_from_env(self, monkeypatch: pytest.MonkeyPatch) -> None:
        monkeypatch.setenv("ORACLE_SLACK_TOKEN", "xoxb-test789")
        data: dict = {"sources": {"slack": {"token": None}}}
        result = _apply_env_vars(data)
        assert result["sources"]["slack"]["token"] == "xoxb-test789"

    def test_openai_key_from_env(self, monkeypatch: pytest.MonkeyPatch) -> None:
        monkeypatch.setenv("OPENAI_API_KEY", "sk-test")
        data: dict = {"llm": {"openai_api_key": None}}
        result = _apply_env_vars(data)
        assert result["llm"]["openai_api_key"] == "sk-test"

    def test_anthropic_key_from_env(self, monkeypatch: pytest.MonkeyPatch) -> None:
        monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-ant-test")
        data: dict = {"llm": {"anthropic_api_key": None}}
        result = _apply_env_vars(data)
        assert result["llm"]["anthropic_api_key"] == "sk-ant-test"

    def test_env_var_does_not_override_explicit_value(
        self, monkeypatch: pytest.MonkeyPatch
    ) -> None:
        monkeypatch.setenv("ORACLE_GITHUB_TOKEN", "from_env")
        data: dict = {"sources": {"github": {"token": "from_yaml"}}}
        result = _apply_env_vars(data)
        assert result["sources"]["github"]["token"] == "from_yaml"

    def test_missing_env_var_leaves_none(self, monkeypatch: pytest.MonkeyPatch) -> None:
        monkeypatch.delenv("ORACLE_GITHUB_TOKEN", raising=False)
        data: dict = {"sources": {"github": {"token": None}}}
        result = _apply_env_vars(data)
        assert result["sources"]["github"]["token"] is None

    def test_env_var_creates_missing_keys(self, monkeypatch: pytest.MonkeyPatch) -> None:
        monkeypatch.setenv("ORACLE_GITHUB_TOKEN", "ghp_new")
        data: dict = {}
        result = _apply_env_vars(data)
        assert result["sources"]["github"]["token"] == "ghp_new"


class TestOracleConfig:
    def test_default_config(self) -> None:
        config = OracleConfig()
        assert config.sources.max_concurrent_clones == 5
        assert config.llm.default_provider == "ollama"
        assert config.vectordb.embeddings.model == "all-MiniLM-L6-v2"
        assert config.rag.min_score == 0.3
        assert config.rag.top_k == 10

    def test_max_concurrent_clones_default(self) -> None:
        config = OracleConfig()
        assert config.sources.max_concurrent_clones == 5

    def test_max_concurrent_clones_override(self) -> None:
        config = OracleConfig(sources={"max_concurrent_clones": 10})  # type: ignore[arg-type]
        assert config.sources.max_concurrent_clones == 10

    def test_invalid_type_rejected(self) -> None:
        with pytest.raises(ValueError):
            OracleConfig(sources={"max_concurrent_clones": "not_a_number"})  # type: ignore[arg-type]

    def test_github_org_config(self) -> None:
        config = OracleConfig(
            sources={  # type: ignore[arg-type]
                "github": {
                    "orgs": [{"name": "RedHatInsights", "depth": 1}],
                }
            }
        )
        assert len(config.sources.github.orgs) == 1
        assert config.sources.github.orgs[0].name == "RedHatInsights"
        assert config.sources.github.orgs[0].depth == 1


class TestLoadConfig:
    def test_load_from_file(self, tmp_path: Path) -> None:
        config_data = {
            "sources": {"max_concurrent_clones": 3},
            "llm": {"default_provider": "openai"},
        }
        config_file = tmp_path / "oracle.yaml"
        config_file.write_text(yaml.dump(config_data))

        config = load_config(extra_paths=[config_file])
        assert config.sources.max_concurrent_clones == 3
        assert config.llm.default_provider == "openai"

    def test_merge_multiple_files(self, tmp_path: Path) -> None:
        base_file = tmp_path / "base.yaml"
        base_file.write_text(yaml.dump({
            "sources": {"max_concurrent_clones": 3},
            "llm": {"default_provider": "ollama"},
        }))

        override_file = tmp_path / "override.yaml"
        override_file.write_text(yaml.dump({
            "llm": {"default_provider": "openai"},
        }))

        config = load_config(extra_paths=[base_file, override_file])
        assert config.sources.max_concurrent_clones == 3
        assert config.llm.default_provider == "openai"

    def test_load_with_env_vars(
        self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
    ) -> None:
        monkeypatch.setenv("ORACLE_GITHUB_TOKEN", "ghp_from_env")
        config_file = tmp_path / "oracle.yaml"
        config_file.write_text(yaml.dump({
            "sources": {"github": {"token": None}},
        }))

        config = load_config(extra_paths=[config_file])
        assert config.sources.github.token == "ghp_from_env"

    def test_load_empty_file(self, tmp_path: Path) -> None:
        config_file = tmp_path / "oracle.yaml"
        config_file.write_text("")

        config = load_config(extra_paths=[config_file])
        assert config.sources.max_concurrent_clones == 5

    def test_load_nonexistent_file(self) -> None:
        config = load_config(extra_paths=[Path("/nonexistent/oracle.yaml")])
        assert config.sources.max_concurrent_clones == 5


class TestJiraConfig:
    def test_default_jira_config(self) -> None:
        config = OracleConfig()
        assert config.sources.jira.url == "https://issues.redhat.com"
        assert config.sources.jira.token is None
        assert config.sources.jira.projects == ["RHCLOUD", "AAP", "ANSTRAT", "INSIGHTS"]
        assert config.sources.jira.max_results == 100
        assert config.sources.jira.include_comments is True
        assert config.sources.jira.history_days == 365

    def test_jira_config_override(self) -> None:
        config = OracleConfig(
            sources={  # type: ignore[arg-type]
                "jira": {
                    "url": "https://jira.example.com",
                    "projects": ["PROJ1"],
                    "history_days": 30,
                }
            }
        )
        assert config.sources.jira.url == "https://jira.example.com"
        assert config.sources.jira.projects == ["PROJ1"]
        assert config.sources.jira.history_days == 30

    def test_jira_token_from_env(self, monkeypatch: pytest.MonkeyPatch) -> None:
        monkeypatch.setenv("ORACLE_JIRA_TOKEN", "jira-pat-test")
        data: dict = {"sources": {"jira": {"token": None}}}
        result = _apply_env_vars(data)
        assert result["sources"]["jira"]["token"] == "jira-pat-test"


class TestWebConfig:
    def test_default_web_config(self) -> None:
        config = OracleConfig()
        assert config.sources.web.urls == []
        assert config.sources.web.timeout == 30

    def test_web_config_override(self) -> None:
        config = OracleConfig(
            sources={  # type: ignore[arg-type]
                "web": {
                    "urls": ["https://example.com"],
                    "timeout": 60,
                }
            }
        )
        assert config.sources.web.urls == ["https://example.com"]
        assert config.sources.web.timeout == 60


class TestSlackConfigDefaults:
    def test_slack_host_default(self) -> None:
        config = OracleConfig()
        assert config.sources.slack.host == "redhat.enterprise.slack.com"

    def test_slack_workspace_id_default(self) -> None:
        config = OracleConfig()
        assert config.sources.slack.workspace_id == "E030G10V24F"

    def test_slack_host_override(self) -> None:
        config = OracleConfig(
            sources={"slack": {"host": "custom.slack.com"}}  # type: ignore[arg-type]
        )
        assert config.sources.slack.host == "custom.slack.com"
