"""Tests for test_runner.common.connection_reader."""

from __future__ import annotations

from pathlib import Path

import pytest

from test_runner.common.connection_reader import (
    load_connections_toml,
    resolve_default_source_connection,
    resolve_default_target_connection,
    resolve_named_connection,
)


SAMPLE_TOML = """\
[connections.default]
host = "127.0.0.1"
port = 1433
database = "testdb"
username = "sa"
password = "secret"
trust_server_certificate = "yes"
encrypt = "no"

[connections.staging]
host = "staging-host"
port = 1433
database = "staging_db"
username = "app_user"
password = "staging_pw"
"""

SAMPLE_TOML_WITH_DEFAULT = """\
default_connection_name = "default"

[connections.default]
host = "127.0.0.1"
port = 1433
database = "testdb"
username = "sa"
password = "secret"

[connections.staging]
host = "staging-host"
port = 1433
database = "staging_db"
username = "app_user"
password = "staging_pw"
"""

SAMPLE_SNOWFLAKE_CONFIG = """\
default_connection_name = "my_sf"

[connections.my_sf]
account = "myaccount"
user = "myuser"
database = "mydb"
warehouse = "mywh"
role = "myrole"
"""


@pytest.fixture()
def toml_project(tmp_path: Path) -> Path:
    """Create a project-level .snowflake/snowct/sqlserver.toml."""
    toml_dir = tmp_path / ".snowflake" / "snowct"
    toml_dir.mkdir(parents=True)
    (toml_dir / "sqlserver.toml").write_text(SAMPLE_TOML)
    return tmp_path


@pytest.fixture()
def toml_home(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
    """Patch Path.home() and create user-level sqlserver.toml."""
    home = tmp_path / "fake_home"
    toml_dir = home / ".snowflake" / "snowct"
    toml_dir.mkdir(parents=True)
    (toml_dir / "sqlserver.toml").write_text(SAMPLE_TOML)
    monkeypatch.setattr(Path, "home", staticmethod(lambda: home))
    return home


# ---------------------------------------------------------------------------
# load_connections_toml
# ---------------------------------------------------------------------------

class TestLoadConnectionsToml:
    def test_loads_from_project_root(self, toml_project: Path):
        conns = load_connections_toml("sqlserver.toml", toml_project)
        assert "default" in conns
        assert conns["default"]["host"] == "127.0.0.1"
        assert conns["default"]["port"] == 1433

    def test_loads_from_home_fallback(self, toml_home: Path):
        conns = load_connections_toml("sqlserver.toml", project_root=None)
        assert "default" in conns
        assert conns["default"]["database"] == "testdb"

    def test_project_takes_priority_over_home(
        self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch,
    ):
        home = tmp_path / "home"
        home_dir = home / ".snowflake" / "snowct"
        home_dir.mkdir(parents=True)
        (home_dir / "sqlserver.toml").write_text(
            '[connections.default]\nhost = "home-host"\n'
        )
        monkeypatch.setattr(Path, "home", staticmethod(lambda: home))

        proj = tmp_path / "proj"
        proj_dir = proj / ".snowflake" / "snowct"
        proj_dir.mkdir(parents=True)
        (proj_dir / "sqlserver.toml").write_text(
            '[connections.default]\nhost = "project-host"\n'
        )

        conns = load_connections_toml("sqlserver.toml", project_root=proj)
        assert conns["default"]["host"] == "project-host"

    def test_returns_empty_when_no_file(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
        monkeypatch.setattr(Path, "home", staticmethod(lambda: tmp_path / "nope"))
        conns = load_connections_toml("sqlserver.toml", project_root=tmp_path)
        assert conns == {}

    def test_multiple_connections(self, toml_project: Path):
        conns = load_connections_toml("sqlserver.toml", toml_project)
        assert "default" in conns
        assert "staging" in conns
        assert conns["staging"]["host"] == "staging-host"


# ---------------------------------------------------------------------------
# resolve_named_connection
# ---------------------------------------------------------------------------

class TestResolveNamedConnection:
    def test_resolves_default(self, toml_project: Path):
        result = resolve_named_connection("default", "sqlserver.toml", toml_project)
        assert result["host"] == "127.0.0.1"
        assert result["database"] == "testdb"
        assert result["username"] == "sa"

    def test_resolves_staging(self, toml_project: Path):
        result = resolve_named_connection("staging", "sqlserver.toml", toml_project)
        assert result["host"] == "staging-host"
        assert result["database"] == "staging_db"

    def test_raises_key_error_for_missing_name(self, toml_project: Path):
        with pytest.raises(KeyError, match="nonexistent"):
            resolve_named_connection("nonexistent", "sqlserver.toml", toml_project)

    def test_error_message_lists_available(self, toml_project: Path):
        with pytest.raises(KeyError, match="default"):
            resolve_named_connection("nope", "sqlserver.toml", toml_project)

    def test_returns_plain_dict(self, toml_project: Path):
        result = resolve_named_connection("default", "sqlserver.toml", toml_project)
        assert isinstance(result, dict)

    def test_home_fallback(self, toml_home: Path):
        result = resolve_named_connection("default", "sqlserver.toml")
        assert result["host"] == "127.0.0.1"


# ---------------------------------------------------------------------------
# resolve_default_source_connection
# ---------------------------------------------------------------------------

class TestResolveDefaultSourceConnection:
    def test_resolves_from_project_toml(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
        home = tmp_path / "empty_home"
        home.mkdir()
        monkeypatch.setattr(Path, "home", staticmethod(lambda: home))

        toml_dir = tmp_path / ".snowflake" / "snowct"
        toml_dir.mkdir(parents=True)
        (toml_dir / "sqlserver.toml").write_text(SAMPLE_TOML_WITH_DEFAULT)

        result = resolve_default_source_connection("sqlserver.toml", tmp_path)
        assert result["host"] == "127.0.0.1"
        assert result["database"] == "testdb"

    def test_resolves_from_home_fallback(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
        home = tmp_path / "fake_home"
        toml_dir = home / ".snowflake" / "snowct"
        toml_dir.mkdir(parents=True)
        (toml_dir / "sqlserver.toml").write_text(SAMPLE_TOML_WITH_DEFAULT)
        monkeypatch.setattr(Path, "home", staticmethod(lambda: home))

        project = tmp_path / "project"
        project.mkdir()

        result = resolve_default_source_connection("sqlserver.toml", project)
        assert result["host"] == "127.0.0.1"

    def test_raises_when_no_toml_exists(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
        home = tmp_path / "empty_home"
        home.mkdir()
        monkeypatch.setattr(Path, "home", staticmethod(lambda: home))

        with pytest.raises(FileNotFoundError, match="No source connection TOML"):
            resolve_default_source_connection("sqlserver.toml", tmp_path)

    def test_raises_when_no_default_connection_name(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
        home = tmp_path / "empty_home"
        home.mkdir()
        monkeypatch.setattr(Path, "home", staticmethod(lambda: home))

        toml_dir = tmp_path / ".snowflake" / "snowct"
        toml_dir.mkdir(parents=True)
        (toml_dir / "sqlserver.toml").write_text(SAMPLE_TOML)

        with pytest.raises(FileNotFoundError, match="No source connection TOML"):
            resolve_default_source_connection("sqlserver.toml", tmp_path)

    def test_raises_when_default_name_not_in_connections(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
        home = tmp_path / "empty_home"
        home.mkdir()
        monkeypatch.setattr(Path, "home", staticmethod(lambda: home))

        toml_dir = tmp_path / ".snowflake" / "snowct"
        toml_dir.mkdir(parents=True)
        (toml_dir / "sqlserver.toml").write_text(
            'default_connection_name = "nonexistent"\n\n'
            '[connections.other]\nhost = "x"\n'
        )

        with pytest.raises(KeyError, match="nonexistent"):
            resolve_default_source_connection("sqlserver.toml", tmp_path)

    def test_project_level_takes_priority(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
        home = tmp_path / "fake_home"
        home_dir = home / ".snowflake" / "snowct"
        home_dir.mkdir(parents=True)
        (home_dir / "sqlserver.toml").write_text(
            'default_connection_name = "default"\n\n'
            '[connections.default]\nhost = "home-host"\n'
        )
        monkeypatch.setattr(Path, "home", staticmethod(lambda: home))

        proj_dir = tmp_path / ".snowflake" / "snowct"
        proj_dir.mkdir(parents=True)
        (proj_dir / "sqlserver.toml").write_text(
            'default_connection_name = "default"\n\n'
            '[connections.default]\nhost = "project-host"\n'
        )

        result = resolve_default_source_connection("sqlserver.toml", tmp_path)
        assert result["host"] == "project-host"


# ---------------------------------------------------------------------------
# resolve_default_target_connection
# ---------------------------------------------------------------------------

class TestResolveDefaultTargetConnection:
    def test_resolves_from_project_config_toml(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
        home = tmp_path / "empty_home"
        home.mkdir()
        monkeypatch.setattr(Path, "home", staticmethod(lambda: home))

        sf_dir = tmp_path / ".snowflake"
        sf_dir.mkdir(parents=True)
        (sf_dir / "config.toml").write_text(SAMPLE_SNOWFLAKE_CONFIG)

        result = resolve_default_target_connection(tmp_path)
        assert result["account"] == "myaccount"
        assert result["user"] == "myuser"
        assert result["name"] == "my_sf"
        assert result.get("mode", "name") == "name"

    def test_resolves_from_home_fallback(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
        home = tmp_path / "fake_home"
        sf_dir = home / ".snowflake"
        sf_dir.mkdir(parents=True)
        (sf_dir / "config.toml").write_text(SAMPLE_SNOWFLAKE_CONFIG)
        monkeypatch.setattr(Path, "home", staticmethod(lambda: home))

        project = tmp_path / "project"
        project.mkdir()

        result = resolve_default_target_connection(project)
        assert result["account"] == "myaccount"
        assert result["name"] == "my_sf"

    def test_raises_when_no_config_toml(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
        home = tmp_path / "empty_home"
        home.mkdir()
        monkeypatch.setattr(Path, "home", staticmethod(lambda: home))

        with pytest.raises(FileNotFoundError, match="No Snowflake config.toml"):
            resolve_default_target_connection(tmp_path)

    def test_raises_when_default_name_not_in_connections(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
        home = tmp_path / "empty_home"
        home.mkdir()
        monkeypatch.setattr(Path, "home", staticmethod(lambda: home))

        sf_dir = tmp_path / ".snowflake"
        sf_dir.mkdir(parents=True)
        (sf_dir / "config.toml").write_text(
            'default_connection_name = "missing"\n\n'
            '[connections.other]\naccount = "x"\n'
        )

        with pytest.raises(KeyError, match="missing"):
            resolve_default_target_connection(tmp_path)

    def test_skips_config_without_default_name(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
        home = tmp_path / "fake_home"
        sf_dir = home / ".snowflake"
        sf_dir.mkdir(parents=True)
        (sf_dir / "config.toml").write_text(SAMPLE_SNOWFLAKE_CONFIG)
        monkeypatch.setattr(Path, "home", staticmethod(lambda: home))

        proj_sf = tmp_path / ".snowflake"
        proj_sf.mkdir(parents=True)
        (proj_sf / "config.toml").write_text(
            '[connections.other]\naccount = "proj"\n'
        )

        result = resolve_default_target_connection(tmp_path)
        assert result["account"] == "myaccount", \
            "should fall through project-level (no default_connection_name) to home-level"

    def test_sets_name_key_on_result(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
        home = tmp_path / "empty_home"
        home.mkdir()
        monkeypatch.setattr(Path, "home", staticmethod(lambda: home))

        sf_dir = tmp_path / ".snowflake"
        sf_dir.mkdir(parents=True)
        (sf_dir / "config.toml").write_text(SAMPLE_SNOWFLAKE_CONFIG)

        result = resolve_default_target_connection(tmp_path)
        assert result["name"] == "my_sf"

    def test_project_level_takes_priority(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
        home = tmp_path / "fake_home"
        home_sf = home / ".snowflake"
        home_sf.mkdir(parents=True)
        (home_sf / "config.toml").write_text(
            'default_connection_name = "home_conn"\n\n'
            '[connections.home_conn]\naccount = "home-acct"\n'
        )
        monkeypatch.setattr(Path, "home", staticmethod(lambda: home))

        proj_sf = tmp_path / ".snowflake"
        proj_sf.mkdir(parents=True)
        (proj_sf / "config.toml").write_text(
            'default_connection_name = "proj_conn"\n\n'
            '[connections.proj_conn]\naccount = "proj-acct"\n'
        )

        result = resolve_default_target_connection(tmp_path)
        assert result["account"] == "proj-acct"
