"""Tests for ``mgf.apiprobe.core.matchers.format``."""

from __future__ import annotations

import pytest

from mgf.apiprobe.core.matchers.format import (
    is_email,
    is_iso8601_z,
    is_url,
    is_uuid,
)


class TestIsUuid:
    @pytest.mark.parametrize(
        "value",
        [
            "550e8400-e29b-41d4-a716-446655440000",  # v4
            "f81d4fae-7dec-11d0-a765-00a0c91e6bf6",  # v1
            "017f22e2-79b0-7cc3-98c4-dc0c0c07398f",  # v7
            "550E8400-E29B-41D4-A716-446655440000",  # uppercase
        ],
    )
    def test_accepts_valid_uuids(self, value: str) -> None:
        assert is_uuid()(value) is True

    @pytest.mark.parametrize(
        "value",
        [
            "not-a-uuid",
            "550e8400-e29b-41d4-a716-44665544000",  # too short
            "550e8400-e29b-41d4-a716-4466554400000",  # too long
            "",
            42,
            None,
        ],
    )
    def test_rejects_invalid(self, value: object) -> None:
        assert is_uuid()(value) is False


class TestIsIso8601Z:
    @pytest.mark.parametrize(
        "value",
        [
            "2026-04-29T12:34:56Z",
            "2026-04-29T12:34:56.789Z",
            "2026-04-29T12:34:56+00:00",
            "2026-04-29T12:34:56-05:00",
        ],
    )
    def test_accepts_valid(self, value: str) -> None:
        assert is_iso8601_z()(value) is True

    @pytest.mark.parametrize(
        "value",
        [
            "2026-04-29T12:34:56",  # naive — explicit reject
            "2026-04-29 12:34:56Z",  # space instead of T (still parses but allowed)
            "April 29, 2026",
            "not a date",
            "",
            42,
        ],
    )
    def test_rejects_invalid(self, value: object) -> None:
        # Note: "2026-04-29 12:34:56Z" — fromisoformat accepts space-separated;
        # but our matcher REQUIRES Z or explicit offset, so it should still pass
        # the suffix check. Let's verify explicitly.
        if value == "2026-04-29 12:34:56Z":
            # Space-form with Z is parseable; we accept it.
            assert is_iso8601_z()(value) is True
            return
        assert is_iso8601_z()(value) is False

    def test_rejects_naive_explicitly(self) -> None:
        # Explicit test: this is the most common provider bug
        # (drops the TZ suffix).
        assert is_iso8601_z()("2026-04-29T12:34:56") is False


class TestIsUrl:
    @pytest.mark.parametrize(
        "value",
        [
            "https://example.com",
            "http://example.com",
            "https://api.example.com:8080/v1/users?id=1",
            "https://example.com/",
        ],
    )
    def test_accepts_valid(self, value: str) -> None:
        assert is_url()(value) is True

    @pytest.mark.parametrize(
        "value",
        [
            "ftp://example.com",  # not http/https
            "example.com",  # missing scheme
            "https://example com",  # whitespace
            "",
            42,
        ],
    )
    def test_rejects_invalid(self, value: object) -> None:
        assert is_url()(value) is False


class TestIsEmail:
    @pytest.mark.parametrize(
        "value",
        [
            "alice@example.com",
            "alice+tag@sub.example.com",
            "a.b@c.d",
        ],
    )
    def test_accepts_valid(self, value: str) -> None:
        assert is_email()(value) is True

    @pytest.mark.parametrize(
        "value",
        [
            "alice@",
            "@example.com",
            "alice example.com",  # space, no @
            "alice@example",  # no TLD
            "",
            42,
        ],
    )
    def test_rejects_invalid(self, value: object) -> None:
        assert is_email()(value) is False
