"""Identifier type detection and routing for universal resolution.

Detects identifier types (DOI, arXiv, HAL, DBLP, OpenReview, title)
from free-form strings and routes to the appropriate client.
"""

from __future__ import annotations

import enum
import re

__all__ = ["IdentifierType", "detect_identifier"]


class IdentifierType(enum.Enum):
    """Scholarly identifier types recognized by the resolver."""

    DOI = "doi"
    ARXIV = "arxiv"
    HAL = "hal"
    DBLP = "dblp"
    OPENREVIEW = "openreview"
    TITLE = "title"


# ── Compiled patterns ────────────────────────────────────────────────────

_DOI_RE = re.compile(
    r"^(?:https?://(?:dx\.)?doi\.org/)?"
    r"(10\.\d{4,}/\S+)$",
    re.IGNORECASE,
)

_ARXIV_RE = re.compile(
    r"^(?:arXiv:?|https?://arxiv\.org/(?:abs|pdf)/)"
    r"(\d{4}\.\d{4,5}(?:v\d+)?|[a-z-]+(?:\.[A-Z]{2})?/\d{7})"
    r"(?:\.pdf)?$",
    re.IGNORECASE,
)

# Bare new-format arXiv IDs: YYMM.NNNNN(vN)? without any prefix
_ARXIV_BARE_RE = re.compile(
    r"^(\d{4}\.\d{4,5}(?:v\d+)?)$",
)

_HAL_RE = re.compile(
    r"^(?:https?://hal\.(?:archives-ouvertes|science)\.fr/)?"
    r"(hal-\d{8}(?:v\d+)?)$",
    re.IGNORECASE,
)

_OPENREVIEW_RE = re.compile(
    r"^https?://openreview\.net/forum\?id=([A-Za-z0-9_-]+)$",
    re.IGNORECASE,
)

# Bare OpenReview prefix: "openreview:_nGgzQjzaRy" or "OpenReview:xyz123"
_OPENREVIEW_BARE_RE = re.compile(
    r"^openreview:([A-Za-z0-9_-]+)$",
    re.IGNORECASE,
)

# DBLP keys look like "conf/nips/VaswaniSPUJGKP17" or "journals/corr/..."
_DBLP_RE = re.compile(
    r"^(?:https?://dblp\.org/rec/)?"
    r"((?:conf|journals|books|series|phd)/[a-zA-Z0-9/]+)$",
)


_PATTERNS: list[tuple[re.Pattern[str], IdentifierType]] = [
    (_DOI_RE, IdentifierType.DOI),
    (_ARXIV_BARE_RE, IdentifierType.ARXIV),
    (_ARXIV_RE, IdentifierType.ARXIV),
    (_HAL_RE, IdentifierType.HAL),
    (_OPENREVIEW_BARE_RE, IdentifierType.OPENREVIEW),
    (_OPENREVIEW_RE, IdentifierType.OPENREVIEW),
    (_DBLP_RE, IdentifierType.DBLP),
]


def detect_identifier(ref: str) -> tuple[IdentifierType, str]:
    """Detect the type and normalized value of a scholarly identifier.

    Args:
        ref: Free-form identifier string (DOI, arXiv ID, URL, title, etc.).

    Returns:
        Tuple of ``(IdentifierType, normalized_value)``.
        For TITLE type, ``normalized_value`` is the original string stripped.
    """
    ref = ref.strip()

    for pattern, id_type in _PATTERNS:
        if m := pattern.match(ref):
            # Group 1 is the normalized value for all patterns
            return id_type, m.group(1)

    # Default: treat as title
    return IdentifierType.TITLE, ref
