import pytest

from inventory_monitor.models import (
    AppConfig,
    NetBoxConfig,
    SnmpConfig,
    SnmpV2Config,
    SnmpV3Config,
    _parse_comma_list,
    _parse_int_versions,
    _safe_int,
    load_config_from_env,
)


class TestParseCommaList:
    def test_empty_string(self):
        assert _parse_comma_list("") == []

    def test_none(self):
        assert _parse_comma_list(None) == []

    def test_single_item(self):
        assert _parse_comma_list("foo") == ["foo"]

    def test_multiple_items(self):
        assert _parse_comma_list("a, b, c") == ["a", "b", "c"]

    def test_strips_whitespace(self):
        assert _parse_comma_list("  x , y ") == ["x", "y"]

    def test_skips_empty_segments(self):
        assert _parse_comma_list("a,,b,") == ["a", "b"]


class TestSafeInt:
    def test_valid_int(self):
        assert _safe_int("42", 0) == 42

    def test_none_returns_default(self):
        assert _safe_int(None, 10) == 10

    def test_empty_returns_default(self):
        assert _safe_int("", 5) == 5

    def test_invalid_returns_default(self):
        assert _safe_int("abc", 7) == 7


class TestParseIntVersions:
    def test_default_when_none(self):
        assert _parse_int_versions(None) == [3, 2]

    def test_default_when_empty(self):
        assert _parse_int_versions("") == [3, 2]

    def test_single_version(self):
        assert _parse_int_versions("2") == [2]

    def test_multiple_versions(self):
        assert _parse_int_versions("3,2") == [3, 2]

    def test_ignores_invalid_versions(self):
        assert _parse_int_versions("3,5,2") == [3, 2]

    def test_ignores_non_numeric(self):
        assert _parse_int_versions("abc,2") == [2]

    def test_all_invalid_returns_default(self):
        assert _parse_int_versions("5,6") == [3, 2]


class TestLoadConfigFromEnv:
    def test_defaults(self):
        cfg = load_config_from_env(env={})
        assert isinstance(cfg, AppConfig)
        assert cfg.snmp.versions == [3, 2]
        assert cfg.snmp.v2.community == "public"
        assert cfg.parallel_jobs == 50
        assert cfg.log_level == "INFO"

    def test_env_overrides(self):
        env = {
            "SNMP_VERSION": "2",
            "SNMP_COMMUNITY": "secret",
            "SNMP_USER": "admin",
            "SNMP_TIMEOUT": "30",
            "SNMP_RETRIES": "3",
            "NETBOX_API_TOKEN": "mytoken",
            "NETBOX_INSTANCE_URL": "https://nb.example.com/",
            "NETBOX_TAGS": "prod,core",
            "NETBOX_TAGS__N": "decom",
            "NETBOX_VERIFY_SSL": "false",
            "PARALLEL_JOBS": "10",
            "LOG_LEVEL": "debug",
            "entPhysicalModelName_excludes": "EXCLUDE1,EXCLUDE2",
        }
        cfg = load_config_from_env(env=env)
        assert cfg.snmp.versions == [2]
        assert cfg.snmp.v2.community == "secret"
        assert cfg.snmp.v3.user == "admin"
        assert cfg.snmp.timeout == 30
        assert cfg.snmp.retries == 3
        assert cfg.netbox.api_token == "mytoken"
        assert cfg.netbox.instance_url == "https://nb.example.com/"
        assert cfg.netbox.tags == ["prod", "core"]
        assert cfg.netbox.tags_exclude == ["decom"]
        assert cfg.netbox.verify_ssl is False
        assert cfg.parallel_jobs == 10
        assert cfg.log_level == "DEBUG"
        assert cfg.model_name_excludes == ["EXCLUDE1", "EXCLUDE2"]

    def test_legacy_excludes_spelling(self):
        env = {"entPhysicalModelName_exludes": "OLD_MODEL"}
        cfg = load_config_from_env(env=env)
        assert cfg.model_name_excludes == ["OLD_MODEL"]

    def test_frozen_dataclass(self):
        cfg = load_config_from_env(env={})
        with pytest.raises(AttributeError):
            cfg.parallel_jobs = 99

    def test_env_file_parameter_loads_custom_file(self, tmp_path):
        """Test that env_file parameter loads from custom file."""
        custom_env = tmp_path / ".env.custom"
        custom_env.write_text(
            "NETBOX_API_TOKEN=custom-token\n"
            "SNMP_COMMUNITY=custom_community\n"
            "PARALLEL_JOBS=25\n"
        )

        cfg = load_config_from_env(env_file=str(custom_env))

        assert cfg.netbox.api_token == "custom-token"
        assert cfg.snmp.v2.community == "custom_community"
        assert cfg.parallel_jobs == 25

    def test_env_file_parameter_default_dotenv(self, tmp_path, monkeypatch):
        """Test that default env_file parameter loads from .env."""
        monkeypatch.chdir(tmp_path)
        default_env = tmp_path / ".env"
        default_env.write_text(
            "NETBOX_API_TOKEN=default-token\n"
            "LOG_LEVEL=WARNING\n"
        )

        cfg = load_config_from_env()  # Uses default .env

        assert cfg.netbox.api_token == "default-token"
        assert cfg.log_level == "WARNING"

    def test_env_parameter_bypasses_file(self):
        """Test that passing env dict bypasses file reading."""
        env = {
            "NETBOX_API_TOKEN": "direct-token",
            "SNMP_TIMEOUT": "99",
        }
        # Even if we pass a non-existent file, it should use the env dict
        cfg = load_config_from_env(env=env, env_file="/nonexistent/.env")

        assert cfg.netbox.api_token == "direct-token"
        assert cfg.snmp.timeout == 99
