import yaml

from nebula_cert_manager.config_gen import TEMPLATE_DIR, render_client_config
from nebula_cert_manager.models import LighthouseConfig


def test_render_client_config(sample_client):
    lighthouses = [
        LighthouseConfig(
            nebula_ip="10.43.0.1",
            public_endpoints=["203.0.113.1"],
            listen_port=44300,
        )
    ]
    ca_cert = "-----BEGIN NEBULA CERTIFICATE-----\nca-data\n-----END NEBULA CERTIFICATE-----\n"

    result = render_client_config(
        ca_cert=ca_cert,
        client=sample_client,
        lighthouses=lighthouses,
    )

    assert "-----BEGIN NEBULA CERTIFICATE-----" in result
    assert "-----BEGIN NEBULA X25519 PRIVATE KEY-----" in result
    assert "10.43.0.1" in result
    assert "203.0.113.1:44300" in result
    assert "am_lighthouse: false" in result
    assert "punch: true" in result

    parsed = yaml.safe_load(result)
    assert "port" not in parsed["listen"]


def test_render_client_config_parseable_yaml(sample_client):
    lighthouses = [
        LighthouseConfig(
            nebula_ip="10.43.0.1",
            public_endpoints=["203.0.113.1"],
            listen_port=44300,
        )
    ]
    ca_cert = "ca-cert-data\n"

    result = render_client_config(
        ca_cert=ca_cert,
        client=sample_client,
        lighthouses=lighthouses,
    )

    parsed = yaml.safe_load(result)
    assert parsed["pki"]["ca"] is not None
    assert parsed["lighthouse"]["am_lighthouse"] is False
    assert "port" not in parsed["listen"]
    assert parsed["firewall"]["outbound"][0]["port"] == "any"


def test_render_multiple_lighthouses(sample_client):
    lighthouses = [
        LighthouseConfig(
            nebula_ip="10.43.0.1",
            public_endpoints=["203.0.113.1"],
            listen_port=44300,
        ),
        LighthouseConfig(
            nebula_ip="10.43.0.2",
            public_endpoints=["203.0.113.2", "203.0.113.3"],
            listen_port=44300,
        ),
    ]

    result = render_client_config(
        ca_cert="ca\n",
        client=sample_client,
        lighthouses=lighthouses,
    )

    parsed = yaml.safe_load(result)
    assert "10.43.0.1" in parsed["static_host_map"]
    assert "10.43.0.2" in parsed["static_host_map"]
    assert len(parsed["lighthouse"]["hosts"]) == 2


def test_render_custom_template(sample_client, tmp_path):
    template = tmp_path / "custom.j2"
    template.write_text("ca: {{ ca_cert }}name: custom")

    lighthouses = []
    result = render_client_config(
        ca_cert="test-ca\n",
        client=sample_client,
        lighthouses=lighthouses,
        template_path=template,
    )

    assert "test-ca" in result
    assert "custom" in result


def test_render_lighthouse_node(sample_client):
    lighthouses = [
        LighthouseConfig(
            nebula_ip="10.43.0.2",
            public_endpoints=["203.0.113.2"],
            listen_port=44300,
        )
    ]

    result = render_client_config(
        ca_cert="ca\n",
        client=sample_client,
        lighthouses=lighthouses,
        am_lighthouse=True,
        listen_port=44300,
    )

    parsed = yaml.safe_load(result)
    assert parsed["lighthouse"]["am_lighthouse"] is True
    assert parsed["listen"]["port"] == 44300
    assert "hosts" not in parsed["lighthouse"]


def test_render_lighthouse_node_no_other_lighthouses(sample_client):
    result = render_client_config(
        ca_cert="ca\n",
        client=sample_client,
        lighthouses=[],
        am_lighthouse=True,
        listen_port=44300,
    )

    parsed = yaml.safe_load(result)
    assert parsed["lighthouse"]["am_lighthouse"] is True
    assert parsed["listen"]["port"] == 44300
    assert "hosts" not in parsed["lighthouse"]


def test_render_default_tun_dev(sample_client):
    result = render_client_config(
        ca_cert="ca\n",
        client=sample_client,
        lighthouses=[],
    )
    parsed = yaml.safe_load(result)
    assert parsed["tun"]["dev"] == "nebula1"


def test_render_custom_tun_dev(sample_client):
    result = render_client_config(
        ca_cert="ca\n",
        client=sample_client,
        lighthouses=[],
        tun_dev="nebula5",
    )
    parsed = yaml.safe_load(result)
    assert parsed["tun"]["dev"] == "nebula5"


def test_render_with_custom_firewall_rules(sample_client):
    lighthouses = [
        LighthouseConfig(
            nebula_ip="10.43.0.1",
            public_endpoints=["203.0.113.1"],
            listen_port=44300,
        )
    ]

    inbound_rules = [
        {"port": "any", "proto": "icmp", "host": "any"},
        {"port": 80, "proto": "tcp", "group": "admin"},
    ]
    outbound_rules = [
        {"port": "any", "proto": "icmp", "host": "any"},
        {"port": "any", "proto": "any", "host": "any"},
    ]

    result = render_client_config(
        ca_cert="ca\n",
        client=sample_client,
        lighthouses=lighthouses,
        inbound_rules=inbound_rules,
        outbound_rules=outbound_rules,
    )

    parsed = yaml.safe_load(result)
    fw = parsed["firewall"]
    assert len(fw["inbound"]) == 2
    assert len(fw["outbound"]) == 2
    assert fw["inbound"][0] == {"port": "any", "proto": "icmp", "host": "any"}
    assert fw["inbound"][1] == {"port": 80, "proto": "tcp", "group": "admin"}
    assert fw["outbound"][1] == {"port": "any", "proto": "any", "host": "any"}


def test_render_base_template_standalone(sample_client):
    """Base template renders only minimal sections (pki, static_host_map, lighthouse, listen, firewall)."""
    lighthouses = [
        LighthouseConfig(
            nebula_ip="10.43.0.1",
            public_endpoints=["203.0.113.1"],
            listen_port=44300,
        )
    ]

    result = render_client_config(
        ca_cert="ca\n",
        client=sample_client,
        lighthouses=lighthouses,
        template_path=TEMPLATE_DIR / "base_config.yml.j2",
    )

    parsed = yaml.safe_load(result)
    # Minimal sections present
    assert "pki" in parsed
    assert "static_host_map" in parsed
    assert "lighthouse" in parsed
    assert "listen" in parsed
    assert "firewall" in parsed
    # Non-minimal sections absent
    assert "static_map" not in parsed
    assert "punchy" not in parsed
    assert "cipher" not in parsed
    assert "relay" not in parsed
    assert "tun" not in parsed
    assert "logging" not in parsed


def test_render_custom_extends_template(sample_client, tmp_path):
    """Custom template can extend base_config.yml.j2 and selectively include sections."""
    template = tmp_path / "custom.j2"
    template.write_text(
        '{% extends "base_config.yml.j2" %}\n'
        '{% block tun %}{% include "sections/tun.yml.j2" %}{% endblock %}\n'
    )

    lighthouses = [
        LighthouseConfig(
            nebula_ip="10.43.0.1",
            public_endpoints=["203.0.113.1"],
            listen_port=44300,
        )
    ]

    result = render_client_config(
        ca_cert="ca\n",
        client=sample_client,
        lighthouses=lighthouses,
        template_path=template,
    )

    parsed = yaml.safe_load(result)
    # Base minimal sections present
    assert "pki" in parsed
    assert "firewall" in parsed
    # Selectively included section present
    assert "tun" in parsed
    assert parsed["tun"]["dev"] == "nebula1"
    # Non-included non-minimal sections absent
    assert "punchy" not in parsed
    assert "cipher" not in parsed


def test_render_non_lighthouse_with_explicit_listen_port(sample_client):
    result = render_client_config(
        ca_cert="ca\n",
        client=sample_client,
        lighthouses=[],
        listen_port=12345,
    )

    parsed = yaml.safe_load(result)
    assert parsed["listen"]["port"] == 12345


def test_render_non_lighthouse_without_listen_port(sample_client):
    result = render_client_config(
        ca_cert="ca\n",
        client=sample_client,
        lighthouses=[],
    )

    parsed = yaml.safe_load(result)
    assert "port" not in parsed["listen"]


def test_render_relay_am_relay(sample_client):
    result = render_client_config(
        ca_cert="ca\n",
        client=sample_client,
        lighthouses=[],
        am_relay=True,
    )

    parsed = yaml.safe_load(result)
    assert parsed["relay"]["am_relay"] is True


def test_render_relay_with_relays(sample_client):
    result = render_client_config(
        ca_cert="ca\n",
        client=sample_client,
        lighthouses=[],
        relays=["10.43.0.1", "10.43.0.2"],
    )

    parsed = yaml.safe_load(result)
    assert parsed["relay"]["relays"] == ["10.43.0.1", "10.43.0.2"]


def test_render_relay_am_relay_with_relays(sample_client):
    result = render_client_config(
        ca_cert="ca\n",
        client=sample_client,
        lighthouses=[],
        am_relay=True,
        relays=["10.43.0.1"],
    )

    parsed = yaml.safe_load(result)
    assert parsed["relay"]["am_relay"] is True
    assert parsed["relay"]["relays"] == ["10.43.0.1"]


def test_render_no_relay_section_when_unconfigured(sample_client):
    result = render_client_config(
        ca_cert="ca\n",
        client=sample_client,
        lighthouses=[],
    )

    parsed = yaml.safe_load(result)
    assert "relay" not in parsed
