import os
import parmed
import pytest
import modrna_params as mp

ALL_FORMS = [(r, t) for r in mp.RESIDUES for t in mp.TERMINI]


def _unit(res, term):
    off = parmed.amber.AmberOFFLibrary.parse(mp.lib_path(res, term))
    name = mp.unit_name(res, term)
    assert name in off, f"{name} missing from its lib"
    return off[name]


@pytest.mark.parametrize("res,term", ALL_FORMS)
def test_parses_named_and_atom_count(res, term):
    unit = _unit(res, term)
    assert len(unit.atoms) == mp.expected_atom_count(res, term)


@pytest.mark.parametrize("res,term", ALL_FORMS)
def test_net_charge_matches_target(res, term):
    unit = _unit(res, term)
    q = sum(a.charge for a in unit.atoms)
    assert q == pytest.approx(mp.NET_CHARGE[term], abs=5e-3)


@pytest.mark.parametrize("res,term", ALL_FORMS)
def test_atom_names_unique(res, term):
    unit = _unit(res, term)
    names = [a.name for a in unit.atoms]
    assert len(names) == len(set(names)), f"duplicate atom names in {res}/{term}"


@pytest.mark.parametrize("term", mp.TERMINI)
def test_psu_is_pseudouridine_not_thiouracil(term):
    unit = _unit("PSU", term)
    assert not any(a.element == 16 for a in unit.atoms)


def test_frcmod_present_and_nonempty():
    assert os.path.getsize(mp.frcmod_path()) > 0


def test_leaprc_lines_reference_existing_files():
    for line in mp.leaprc_lines():
        path = line.split(maxsplit=1)[1]
        assert os.path.exists(path), path
