import math

from idio import (
    DEFAULT_BANK,
    GREEK_MODIFIERS,
    GREEK_NOUNS,
    LATIN_ADJECTIVES,
    LATIN_NOUNS,
    Pattern,
    entropy_bits,
    generate_identifier,
)


def _segment_matches(segment: str) -> bool:
    first, second, third = segment.split("-")
    return (
        (first in LATIN_ADJECTIVES and second in LATIN_NOUNS and third in GREEK_NOUNS)
        or (first in GREEK_MODIFIERS and second in GREEK_NOUNS and third in LATIN_NOUNS)
        or (first in LATIN_NOUNS and second in LATIN_ADJECTIVES and third in GREEK_NOUNS)
    )


def test_identifier_shape_and_words():
    ident = generate_identifier(segments=3)
    segments = ident.split(".")
    assert len(segments) == 3
    for seg in segments:
        parts = seg.split("-")
        assert len(parts) == 3
        assert _segment_matches(seg)


def test_entropy_over_target():
    assert entropy_bits() > 32.0


def test_entropy_matches_manual_calculation():
    a = len(LATIN_ADJECTIVES)
    l = len(LATIN_NOUNS)
    g = len(GREEK_NOUNS)
    m = len(GREEK_MODIFIERS)
    expected = 2 * math.log2((2 * a * l * g) + (m * l * g))
    assert math.isclose(entropy_bits(), expected, rel_tol=1e-12)


def test_custom_segment_count_changes_entropy():
    bits_two = entropy_bits(segments=2)
    bits_three = entropy_bits(segments=3)
    assert bits_three > bits_two
    assert math.isclose(bits_three - bits_two, bits_two - entropy_bits(segments=1), rel_tol=1e-12)


def test_identifier_is_subdomain_safe():
    ident = generate_identifier()
    assert "_" not in ident
    assert ident == ident.lower()

    labels = ident.split(".")
    assert len(labels) == 2  # default segments
    for label in labels:
        assert label[0].isalnum() and label[-1].isalnum()
        assert all(ch.isalnum() or ch == "-" for ch in label)
