"""Tests for netlist module: builder pattern, rendering, template functions."""

import pytest

from mcltspice.netlist import (
    Netlist,
    buck_converter,
    colpitts_oscillator,
    common_emitter_amplifier,
    differential_amplifier,
    h_bridge,
    inverting_amplifier,
    ldo_regulator,
    non_inverting_amplifier,
    rc_lowpass,
    voltage_divider,
)


class TestNetlistBuilder:
    def test_add_resistor(self):
        n = Netlist().add_resistor("R1", "in", "out", "10k")
        assert len(n.components) == 1
        assert n.components[0].name == "R1"
        assert n.components[0].value == "10k"

    def test_add_capacitor(self):
        n = Netlist().add_capacitor("C1", "out", "0", "100n")
        assert len(n.components) == 1
        assert n.components[0].value == "100n"

    def test_add_inductor(self):
        n = Netlist().add_inductor("L1", "a", "b", "10u", series_resistance="0.1")
        assert "Rser=0.1" in n.components[0].params

    def test_chaining(self):
        """Builder methods return self for chaining."""
        n = (
            Netlist("Test")
            .add_resistor("R1", "a", "b", "1k")
            .add_capacitor("C1", "b", "0", "1n")
        )
        assert len(n.components) == 2

    def test_add_voltage_source_dc(self):
        n = Netlist().add_voltage_source("V1", "in", "0", dc="5")
        assert "5" in n.components[0].value

    def test_add_voltage_source_ac(self):
        n = Netlist().add_voltage_source("V1", "in", "0", ac="1")
        assert "AC 1" in n.components[0].value

    def test_add_voltage_source_pulse(self):
        n = Netlist().add_voltage_source(
            "V1", "g", "0", pulse=("0", "5", "0", "1n", "1n", "5u", "10u")
        )
        rendered = n.render()
        assert "PULSE(" in rendered

    def test_add_voltage_source_sin(self):
        n = Netlist().add_voltage_source(
            "V1", "in", "0", sin=("0", "1", "1k")
        )
        rendered = n.render()
        assert "SIN(" in rendered

    def test_add_directive(self):
        n = Netlist().add_directive(".tran 10m")
        assert ".tran 10m" in n.directives

    def test_add_meas(self):
        n = Netlist().add_meas("tran", "vmax", "MAX V(out)")
        assert any("vmax" in d for d in n.directives)


class TestNetlistRender:
    def test_render_contains_title(self):
        n = Netlist("My Circuit")
        text = n.render()
        assert "* My Circuit" in text

    def test_render_contains_components(self):
        n = (
            Netlist()
            .add_resistor("R1", "in", "out", "10k")
            .add_capacitor("C1", "out", "0", "100n")
        )
        text = n.render()
        assert "R1 in out 10k" in text
        assert "C1 out 0 100n" in text

    def test_render_contains_backanno_and_end(self):
        n = Netlist()
        text = n.render()
        assert ".backanno" in text
        assert ".end" in text

    def test_render_includes_directive(self):
        n = Netlist().add_directive(".ac dec 100 1 1meg")
        text = n.render()
        assert ".ac dec 100 1 1meg" in text

    def test_render_includes_comment(self):
        n = Netlist().add_comment("Test comment")
        text = n.render()
        assert "* Test comment" in text

    def test_render_includes_lib(self):
        n = Netlist().add_lib("LT1001")
        text = n.render()
        assert ".lib LT1001" in text


class TestTemplateNetlists:
    """All template functions should return valid Netlist objects."""

    @pytest.mark.parametrize(
        "factory",
        [
            voltage_divider,
            rc_lowpass,
            inverting_amplifier,
            non_inverting_amplifier,
            differential_amplifier,
            common_emitter_amplifier,
            buck_converter,
            ldo_regulator,
            colpitts_oscillator,
            h_bridge,
        ],
    )
    def test_template_returns_netlist(self, factory):
        n = factory()
        assert isinstance(n, Netlist)

    @pytest.mark.parametrize(
        "factory",
        [
            voltage_divider,
            rc_lowpass,
            inverting_amplifier,
            non_inverting_amplifier,
            differential_amplifier,
            common_emitter_amplifier,
            buck_converter,
            ldo_regulator,
            colpitts_oscillator,
            h_bridge,
        ],
    )
    def test_template_has_backanno_and_end(self, factory):
        text = factory().render()
        assert ".backanno" in text
        assert ".end" in text

    @pytest.mark.parametrize(
        "factory",
        [
            voltage_divider,
            rc_lowpass,
            inverting_amplifier,
            non_inverting_amplifier,
            differential_amplifier,
            common_emitter_amplifier,
            buck_converter,
            ldo_regulator,
            colpitts_oscillator,
            h_bridge,
        ],
    )
    def test_template_has_components(self, factory):
        n = factory()
        assert len(n.components) > 0

    @pytest.mark.parametrize(
        "factory",
        [
            voltage_divider,
            rc_lowpass,
            inverting_amplifier,
            non_inverting_amplifier,
            differential_amplifier,
            common_emitter_amplifier,
            buck_converter,
            ldo_regulator,
            colpitts_oscillator,
            h_bridge,
        ],
    )
    def test_template_has_sim_directive(self, factory):
        n = factory()
        # Should have at least one directive starting with a sim type
        sim_types = [".tran", ".ac", ".dc", ".op", ".noise", ".tf"]
        text = n.render()
        assert any(sim in text.lower() for sim in sim_types), (
            f"No simulation directive found in {factory.__name__}"
        )
