import string

import pytest

from cpanel_mailgen.passwords import (
    ALPHABET,
    DEFAULT_LENGTH,
    MIN_LENGTH,
    PasswordError,
    generate_password,
)


def test_default_length():
    assert len(generate_password()) == DEFAULT_LENGTH


@pytest.mark.parametrize("length", [12, 16, 20, 32, 64])
def test_requested_length_is_respected(length):
    assert len(generate_password(length)) == length


def test_too_short_is_refused():
    with pytest.raises(PasswordError, match="minimum"):
        generate_password(MIN_LENGTH - 1)


def test_never_contains_a_semicolon():
    """Un ; casserait le fichier de comptes imapsync, qui n'a pas d'echappement."""
    assert ";" not in ALPHABET
    for _ in range(500):
        assert ";" not in generate_password()


@pytest.mark.parametrize("char", ['"', "'", "\\", "`", "$", " ", ";"])
def test_dangerous_characters_are_excluded(char):
    assert char not in ALPHABET


def test_contains_all_four_classes():
    """cPanel evalue la force du mot de passe : les quatre classes evitent un rejet."""
    for _ in range(200):
        password = generate_password()
        assert any(c in string.ascii_lowercase for c in password)
        assert any(c in string.ascii_uppercase for c in password)
        assert any(c in string.digits for c in password)
        assert any(not c.isalnum() for c in password)


def test_passwords_are_distinct():
    generated = {generate_password() for _ in range(200)}
    assert len(generated) == 200


def test_uses_a_cryptographic_source():
    """Un `random` seede rendrait les mots de passe reproductibles."""
    import random

    random.seed(1234)
    first = generate_password()
    random.seed(1234)
    assert generate_password() != first
