from pathlib import Path

import yaml

from nebula_cert_manager.nebula_config import load_nebula_config

FIXTURES_DIR = Path(__file__).parent / "fixtures"


def test_missing_file(tmp_path):
    cfg = load_nebula_config(tmp_path)
    assert cfg is None


def test_empty_file(tmp_path):
    (tmp_path / "nebula.config.yml").write_text("")
    cfg = load_nebula_config(tmp_path)
    assert cfg is None


def test_network_only(tmp_path):
    data = {
        "network": {"cidr": "10.43.0.0/16"},
    }
    (tmp_path / "nebula.config.yml").write_text(yaml.dump(data))
    cfg = load_nebula_config(tmp_path)
    assert cfg is not None
    assert cfg.network is not None
    assert cfg.network.cidr == "10.43.0.0/16"
    assert cfg.hosts is None
    assert cfg.firewall is None


def test_hosts_with_lighthouses(tmp_path):
    data = {
        "network": {"cidr": "10.43.0.0/16"},
        "hosts": {
            "defaults": {"tun_dev": "nebula1"},
            "hosts": {
                "server1": {
                    "nebula_ip": "10.43.0.1",
                    "public_endpoints": ["203.0.113.1"],
                    "listen_port": 44300,
                },
                "laptop": {
                    "nebula_ip": "10.43.1.1",
                },
            },
        },
    }
    (tmp_path / "nebula.config.yml").write_text(yaml.dump(data))
    cfg = load_nebula_config(tmp_path)
    assert cfg is not None
    assert cfg.hosts is not None
    assert len(cfg.hosts.hosts) == 2
    assert cfg.hosts.hosts["server1"].public_endpoints == ["203.0.113.1"]
    assert cfg.hosts.hosts["server1"].listen_port == 44300
    assert cfg.hosts.hosts["laptop"].public_endpoints is None
    assert cfg.hosts.defaults.tun_dev == "nebula1"


def test_firewall_only(tmp_path):
    data = {
        "firewall": {
            "security_groups": {
                "icmp": {"port": "any", "proto": "icmp", "direction": "any"},
            },
            "firewall_default": {"all": ["icmp"]},
        },
    }
    (tmp_path / "nebula.config.yml").write_text(yaml.dump(data))
    cfg = load_nebula_config(tmp_path)
    assert cfg is not None
    assert cfg.firewall is not None
    assert "icmp" in cfg.firewall.security_groups
    assert cfg.hosts is None


def test_hosts_only(tmp_path):
    data = {
        "hosts": {
            "defaults": {"tun_dev": "nebula1"},
            "hosts": {
                "special": {"nebula_ip": "10.43.1.1", "tun_dev": "nebula2"},
            },
        },
    }
    (tmp_path / "nebula.config.yml").write_text(yaml.dump(data))
    cfg = load_nebula_config(tmp_path)
    assert cfg is not None
    assert cfg.hosts is not None
    assert cfg.hosts.defaults.tun_dev == "nebula1"
    assert cfg.hosts.hosts["special"].tun_dev == "nebula2"
    assert cfg.hosts.hosts["special"].nebula_ip == "10.43.1.1"


def test_all_sections(tmp_path):
    data = {
        "network": {"cidr": "10.43.0.0/16"},
        "hosts": {
            "defaults": {"tun_dev": "nebula1"},
            "hosts": {
                "server1": {
                    "nebula_ip": "10.43.0.1",
                    "public_endpoints": ["203.0.113.1"],
                    "listen_port": 44300,
                },
                "special": {"nebula_ip": "10.43.1.1", "tun_dev": "nebula2"},
            },
        },
        "firewall": {
            "security_groups": {
                "icmp": {"port": "any", "proto": "icmp", "direction": "any"},
            },
            "firewall_default": {"all": ["icmp"]},
        },
    }
    (tmp_path / "nebula.config.yml").write_text(yaml.dump(data))
    cfg = load_nebula_config(tmp_path)
    assert cfg is not None
    assert cfg.network is not None
    assert cfg.hosts is not None
    assert cfg.firewall is not None


def test_partial_firewall_defaults(tmp_path):
    data = {
        "firewall": {
            "security_groups": {
                "icmp": {"port": "any", "proto": "icmp", "direction": "any"},
            },
        },
    }
    (tmp_path / "nebula.config.yml").write_text(yaml.dump(data))
    cfg = load_nebula_config(tmp_path)
    assert cfg is not None
    assert cfg.firewall is not None
    assert cfg.firewall.firewall_default == {}
    assert cfg.firewall.host_groups == {}


def test_full_config_fixture(tmp_path):
    """Load the comprehensive fixture and validate all sections parse correctly."""
    fixture = FIXTURES_DIR / "test_nebula_config_full.yml"
    (tmp_path / "nebula.config.yml").write_text(fixture.read_text())
    cfg = load_nebula_config(tmp_path)
    assert cfg is not None

    # Network
    assert cfg.network is not None
    assert cfg.network.cidr == "10.43.0.0/16"

    # Hosts with lighthouses
    assert cfg.hosts is not None
    assert len(cfg.hosts.hosts) == 5
    lh1 = cfg.hosts.hosts["server-eu-lh-01"]
    assert lh1.nebula_ip == "10.43.0.1"
    assert lh1.listen_port == 22222
    assert len(lh1.public_endpoints) == 2
    assert "[2001:db8::1]" in lh1.public_endpoints
    lh2 = cfg.hosts.hosts["server-us-lh-02"]
    assert lh2.nebula_ip == "10.43.0.2"
    assert lh2.listen_port == 4242
    assert lh2.public_endpoints == ["203.0.113.2"]
    # Non-lighthouse hosts
    assert cfg.hosts.hosts["server-eu-web-01"].public_endpoints is None
    assert cfg.hosts.hosts["dtatarkin-laptop"].nebula_ip == "10.43.1.2"

    # Security groups
    fw = cfg.firewall
    assert fw is not None
    assert len(fw.security_groups) == 9
    assert fw.security_groups["icmp"].proto == "icmp"
    assert fw.security_groups["icmp"].direction == "any"
    assert fw.security_groups["in-highports"].port == "8000-9000"
    assert fw.security_groups["in-nebula"].port == 4242
    assert fw.security_groups["in-nebula"].proto == "udp"

    # Host groups
    assert len(fw.host_groups) == 5
    assert fw.host_groups["server-eu-lh-01"] == ["server", "lighthouse"]
    assert fw.host_groups["dtatarkin-mobile"] == ["mobile"]

    # Firewall rules — per-host
    assert set(fw.firewall_rules.keys()) == {
        "server-eu-lh-01",
        "server-us-lh-02",
        "server-eu-web-01",
    }
    assert "in-http" in fw.firewall_rules["server-eu-web-01"]["all"]
    assert "in-ssh" in fw.firewall_rules["server-eu-web-01"]["admin"]

    # Firewall default
    assert fw.firewall_default["all"] == ["icmp", "out-any"]

    # Hosts overrides
    assert cfg.hosts.defaults.tun_dev == "nebula1"
    assert cfg.hosts.hosts["dtatarkin-mobile"].tun_dev == "nebula-dtatarkin"
    assert cfg.hosts.hosts["server-eu-lh-01"].tun_dev is None
