"""Tests for Layer 1 Validator."""

from cnl_parser import parse
from layer1_validator import validate


def _parse_specs(sentences):
    """Parse a list of CNL sentences."""
    return [parse(s) for s in sentences]


_SAMPLE_SENTENCES = [
    "The sensory neuron MUST fire ONLY IF membrane potential exceeds 1.0",
    "The sensory neuron MUST NOT fire DURING the refractory period of 0.002 seconds",
    "The sensory neuron membrane potential MUST decay WITH time constant of 0.02 seconds",
    "The connection from sensory neuron to motor neuron MUST have WITH synaptic weight of 1.0",
]


def test_all_invariants_pass():
    specs = _parse_specs(_SAMPLE_SENTENCES)
    params = {
        "threshold": 1.0,
        "resting_potential": 0.0,
        "refractory_period": 0.002,
        "tau": 0.02,
        "reset_potential": 0.0,
        "current_voltage": 0.5,
    }
    report = validate(specs, params)
    assert report["overall"] is True
    assert len(report["failed"]) == 0
    assert len(report["passed"]) == 5


def test_threshold_invariant_fails():
    specs = _parse_specs(_SAMPLE_SENTENCES)
    params = {
        "threshold": -0.1,  # below resting potential
        "resting_potential": 0.0,
        "refractory_period": 0.002,
        "tau": 0.02,
        "reset_potential": 0.0,
        "current_voltage": 0.5,
    }
    report = validate(specs, params)
    assert report["overall"] is False
    failed_names = [f["name"] for f in report["failed"]]
    assert "threshold_above_resting" in failed_names


def test_refractory_invariant_fails():
    specs = _parse_specs(_SAMPLE_SENTENCES)
    params = {
        "threshold": 1.0,
        "resting_potential": 0.0,
        "refractory_period": 0,  # zero refractory period
        "tau": 0.02,
        "reset_potential": 0.0,
        "current_voltage": 0.5,
    }
    report = validate(specs, params)
    assert report["overall"] is False
    failed_names = [f["name"] for f in report["failed"]]
    assert "refractory_period_positive" in failed_names


def test_tau_invariant_fails():
    specs = _parse_specs(_SAMPLE_SENTENCES)
    params = {
        "threshold": 1.0,
        "resting_potential": 0.0,
        "refractory_period": 0.002,
        "tau": 0,  # zero time constant
        "reset_potential": 0.0,
        "current_voltage": 0.5,
    }
    report = validate(specs, params)
    assert report["overall"] is False
    failed_names = [f["name"] for f in report["failed"]]
    assert "time_constant_positive" in failed_names
    assert "membrane_potential_decays_toward_rest" in failed_names


def test_reset_above_threshold_fails():
    specs = _parse_specs(_SAMPLE_SENTENCES)
    params = {
        "threshold": 1.0,
        "resting_potential": 0.0,
        "refractory_period": 0.002,
        "tau": 0.02,
        "reset_potential": 1.5,  # above threshold
        "current_voltage": 0.5,
    }
    report = validate(specs, params)
    assert report["overall"] is False
    failed_names = [f["name"] for f in report["failed"]]
    assert "reset_at_or_below_threshold" in failed_names


def test_report_structure():
    specs = _parse_specs(_SAMPLE_SENTENCES)
    params = {
        "threshold": 1.0,
        "resting_potential": 0.0,
        "refractory_period": 0.002,
        "tau": 0.02,
        "reset_potential": 0.0,
        "current_voltage": 0.5,
    }
    report = validate(specs, params)
    assert "passed" in report
    assert "failed" in report
    assert "overall" in report
    assert isinstance(report["passed"], list)
    assert isinstance(report["failed"], list)
    assert isinstance(report["overall"], bool)
