import pytest

from tests.conftest import invalid_postcodes, valid_postcodes
from wojtek.uk_postcodes.validators import _is_special_postcode, is_valid_postcode


def test_valid_postcodes() -> None:
    """Test validation for standard postcodes."""
    for postcode in valid_postcodes():
        assert is_valid_postcode(postcode) is True


def test_invalid_postcode() -> None:
    """Test validation on invalid postcodes."""
    for postcode in invalid_postcodes():
        assert is_valid_postcode(postcode) is False


def test_valid_special_postcode(special_postcodes: set[str]) -> None:
    """Test validation for special postcodes."""
    for postcode in special_postcodes:
        assert is_valid_postcode(postcode, allow_special=True)


def test_special_postcode_when_not_allowed(special_postcodes: set[str]) -> None:
    """Test validation for special postcodes when not allowed."""
    for postcode in special_postcodes:
        assert is_valid_postcode(postcode, allow_special=False) is False


def test_invalid_type_postcode() -> None:
    """Test validation for invalid type postcodes."""
    assert is_valid_postcode(123) is False


@pytest.mark.parametrize(
    ("postcode", "require_full", "valid"),
    [
        ("SW1A", True, False),
        ("SW1A", False, True),
        ("VV1A", False, False),
        ("X1", False, False),
    ],
)
def test_partial_postcode_validation(postcode: str, require_full: bool, valid: bool) -> None:
    """Test validation for partial postcodes."""
    assert is_valid_postcode(postcode, require_full=require_full) is valid


@pytest.mark.parametrize(
    ("postcode", "require_full", "valid"),
    [
        ("BFPO", True, False),
        ("BFPO", False, True),
        ("BFPO 801", True, True),
        ("BFPO 801", False, True),
    ],
)
def test_is_special_postcode(postcode: str, require_full: bool, valid: bool) -> None:
    """Test _is_special_postcode function."""
    assert _is_special_postcode(postcode, require_full=require_full) is valid


@pytest.mark.parametrize(
    ("postcode", "require_full", "valid"),
    [
        ("SW1A", True, False),
        ("SW1A", False, True),
        ("SW1A 1AA", True, True),
        ("SW1A 1AA", False, True),
    ],
)
def _is_standard_postcode(postcode: str, require_full: bool, valid: bool) -> None:
    """Test _is_special_postcode function."""
    assert _is_standard_postcode(postcode, require_full=require_full) is valid
