"""Unit tests for resolver — detect_identifier + IdentifierType."""

from __future__ import annotations

import pytest

from axm_bib.resolver import IdentifierType, detect_identifier


class TestDetectDOI:
    """DOI detection tests."""

    def test_plain_doi(self) -> None:
        typ, val = detect_identifier("10.1145/363235.363259")
        assert typ is IdentifierType.DOI
        assert val == "10.1145/363235.363259"

    def test_doi_url(self) -> None:
        typ, val = detect_identifier("https://doi.org/10.1145/363235.363259")
        assert typ is IdentifierType.DOI
        assert val == "10.1145/363235.363259"

    def test_doi_dx_url(self) -> None:
        typ, val = detect_identifier("https://dx.doi.org/10.1145/363235.363259")
        assert typ is IdentifierType.DOI
        assert val == "10.1145/363235.363259"

    def test_arxiv_doi(self) -> None:
        """arXiv DOIs (10.48550/arXiv.*) detected as DOI, not arXiv."""
        typ, val = detect_identifier("10.48550/arXiv.1706.03762")
        assert typ is IdentifierType.DOI
        assert val == "10.48550/arXiv.1706.03762"


class TestDetectArXiv:
    """arXiv ID detection tests."""

    def test_arxiv_prefix(self) -> None:
        typ, val = detect_identifier("arXiv:1706.03762")
        assert typ is IdentifierType.ARXIV
        assert val == "1706.03762"

    def test_arxiv_url(self) -> None:
        typ, val = detect_identifier("https://arxiv.org/abs/1706.03762")
        assert typ is IdentifierType.ARXIV
        assert val == "1706.03762"

    def test_arxiv_pdf_url(self) -> None:
        typ, val = detect_identifier("https://arxiv.org/pdf/1706.03762.pdf")
        assert typ is IdentifierType.ARXIV
        assert val == "1706.03762"

    def test_arxiv_versioned(self) -> None:
        typ, val = detect_identifier("arXiv:1706.03762v2")
        assert typ is IdentifierType.ARXIV
        assert val == "1706.03762v2"

    def test_arxiv_old_format(self) -> None:
        typ, val = detect_identifier("arXiv:math/0102101")
        assert typ is IdentifierType.ARXIV
        assert val == "math/0102101"

    def test_arxiv_bare_new_format(self) -> None:
        """Bare arXiv ID without prefix should be detected."""
        typ, val = detect_identifier("2210.02406")
        assert typ is IdentifierType.ARXIV
        assert val == "2210.02406"

    def test_arxiv_bare_versioned(self) -> None:
        typ, val = detect_identifier("2210.02406v2")
        assert typ is IdentifierType.ARXIV
        assert val == "2210.02406v2"

    def test_arxiv_bare_five_digit(self) -> None:
        typ, val = detect_identifier("2301.12345")
        assert typ is IdentifierType.ARXIV
        assert val == "2301.12345"


class TestDetectHAL:
    """HAL ID detection tests."""

    def test_hal_id(self) -> None:
        typ, val = detect_identifier("hal-01234567")
        assert typ is IdentifierType.HAL
        assert val == "hal-01234567"

    def test_hal_versioned(self) -> None:
        typ, val = detect_identifier("hal-01234567v2")
        assert typ is IdentifierType.HAL
        assert val == "hal-01234567v2"

    def test_hal_url(self) -> None:
        typ, val = detect_identifier("https://hal.archives-ouvertes.fr/hal-01234567")
        assert typ is IdentifierType.HAL
        assert val == "hal-01234567"


class TestDetectOpenReview:
    """OpenReview detection tests."""

    def test_openreview_url(self) -> None:
        typ, val = detect_identifier("https://openreview.net/forum?id=xyz123")
        assert typ is IdentifierType.OPENREVIEW
        assert val == "xyz123"

    def test_openreview_bare_prefix(self) -> None:
        """AC1: openreview:_nGgzQjzaRy → OPENREVIEW."""
        typ, val = detect_identifier("openreview:_nGgzQjzaRy")
        assert typ is IdentifierType.OPENREVIEW
        assert val == "_nGgzQjzaRy"

    def test_openreview_bare_simple(self) -> None:
        """AC2: openreview:xyz123 → OPENREVIEW."""
        typ, val = detect_identifier("openreview:xyz123")
        assert typ is IdentifierType.OPENREVIEW
        assert val == "xyz123"

    def test_openreview_url_unchanged(self) -> None:
        """AC3: existing URL detection is unchanged."""
        typ, val = detect_identifier("https://openreview.net/forum?id=abc")
        assert typ is IdentifierType.OPENREVIEW
        assert val == "abc"

    def test_openreview_bare_empty_is_title(self) -> None:
        """Edge: openreview: with no ID falls through to TITLE."""
        typ, _ = detect_identifier("openreview:")
        assert typ is IdentifierType.TITLE

    def test_openreview_bare_case_insensitive(self) -> None:
        """Edge: OpenReview:abc is case-insensitive."""
        typ, val = detect_identifier("OpenReview:abc")
        assert typ is IdentifierType.OPENREVIEW
        assert val == "abc"


class TestDetectDBLP:
    """DBLP key detection tests."""

    def test_dblp_conf_key(self) -> None:
        typ, val = detect_identifier("conf/nips/VaswaniSPUJGKP17")
        assert typ is IdentifierType.DBLP
        assert val == "conf/nips/VaswaniSPUJGKP17"

    def test_dblp_url(self) -> None:
        typ, val = detect_identifier("https://dblp.org/rec/conf/nips/VaswaniSPUJGKP17")
        assert typ is IdentifierType.DBLP
        assert val == "conf/nips/VaswaniSPUJGKP17"


class TestDetectTitle:
    """Title (fallback) detection tests."""

    def test_plain_title(self) -> None:
        typ, val = detect_identifier("Attention Is All You Need")
        assert typ is IdentifierType.TITLE
        assert val == "Attention Is All You Need"

    def test_empty_string(self) -> None:
        typ, val = detect_identifier("")
        assert typ is IdentifierType.TITLE
        assert val == ""

    def test_whitespace(self) -> None:
        typ, val = detect_identifier("   ")
        assert typ is IdentifierType.TITLE
        assert val == ""

    @pytest.mark.parametrize(
        "ref",
        [
            "Some random paper about transformers",
            "A Survey on Deep Learning",
            "12345",
        ],
    )
    def test_non_matching_strings(self, ref: str) -> None:
        typ, _ = detect_identifier(ref)
        assert typ is IdentifierType.TITLE
