"""Tests for HeuristicCyclicScorer."""
import pytest

from peptidegym.peptide.cyclic_scoring import HeuristicCyclicScorer


@pytest.fixture
def scorer():
    return HeuristicCyclicScorer()


def test_scorer_returns_dict(scorer):
    """score() returns a dictionary."""
    result = scorer.score("ACGLVA", cyclization_type="head_to_tail")
    assert isinstance(result, dict)


def test_cyclization_bonus_valid_head_to_tail(scorer):
    """head_to_tail cyclization with 6+ residues should give bonus of 1.0."""
    result = scorer.score("ACGLVA", cyclization_type="head_to_tail")
    assert result["cyclization_bonus"] == pytest.approx(1.0)


def test_cyclization_bonus_invalid_too_short(scorer):
    """head_to_tail with 2 residues is too short: bonus = 0.0."""
    result = scorer.score("AC", cyclization_type="head_to_tail")
    assert result["cyclization_bonus"] == pytest.approx(0.0)


def test_cyclization_bonus_disulfide_with_cys(scorer):
    """disulfide cyclization with 2+ Cys residues should give 1.0."""
    result = scorer.score("ACGCA", cyclization_type="disulfide")
    assert result["cyclization_bonus"] == pytest.approx(1.0)


def test_cyclization_bonus_disulfide_without_cys(scorer):
    """disulfide cyclization without enough Cys should give 0.0."""
    result = scorer.score("AGGGA", cyclization_type="disulfide")
    assert result["cyclization_bonus"] == pytest.approx(0.0)


def test_cyclization_bonus_sidechain_with_K_and_D(scorer):
    """sidechain lactam with K and D present should give 1.0."""
    result = scorer.score("AKDGL", cyclization_type="sidechain")
    assert result["cyclization_bonus"] == pytest.approx(1.0)


def test_cyclization_bonus_none(scorer):
    """No cyclization type = 0 bonus."""
    result = scorer.score("ACGLVA", cyclization_type="none")
    assert result["cyclization_bonus"] == pytest.approx(0.0)


def test_permeability_score_range(scorer):
    """permeability_score should be in [0, 1]."""
    for seq in ["AGLVFP", "KRKRKR", "WWWWWW", "A"]:
        result = scorer.score(seq)
        assert 0.0 <= result["permeability_score"] <= 1.0


def test_structural_score_range(scorer):
    """structural_score should be in [0, 1]."""
    for length in [3, 6, 10, 15, 25]:
        seq = "A" * length
        result = scorer.score(seq)
        assert 0.0 <= result["structural_score"] <= 1.0


def test_synthetic_score_no_rare(scorer):
    """Sequence of common residues should have high synthetic_score."""
    result = scorer.score("AGLVFP")
    assert result["synthetic_score"] > 0.5


def test_synthetic_score_with_rare_residues(scorer):
    """Sequence heavy in W and M should have lower synthetic_score."""
    rare = scorer.score("WWMWMW")
    common = scorer.score("AGLVFP")
    assert rare["synthetic_score"] < common["synthetic_score"]


def test_scorer_short_sequence(scorer):
    """Single-residue sequence should not crash."""
    result = scorer.score("A")
    assert isinstance(result, dict)
    assert len(result) == 4
