from __future__ import annotations

import re
from urllib.parse import urlparse

from app.services.domains.doi.normalize import normalize_doi
from app.services.domains.publication_identifiers.types import IdentifierKind

ARXIV_ABS_RE = re.compile(r"\barxiv:\s*([a-z-]+/\d{7}|\d{4}\.\d{4,5})(v\d+)?\b", re.I)
ARXIV_RAW_RE = re.compile(r"^([a-z-]+/\d{7}|\d{4}\.\d{4,5})(v\d+)?$", re.I)
ARXIV_PATH_RE = re.compile(r"^/(?:abs|pdf|html|ps|format)/([a-z-]+/\d{7}|\d{4}\.\d{4,5})(v\d+)?(?:\.pdf)?/?$", re.I)
PMCID_RE = re.compile(r"\b(PMC\d+)\b", re.I)
PUBMED_PATH_RE = re.compile(r"^/(\d+)/?$")


def normalize_identifier(kind: IdentifierKind, value: str | None) -> str | None:
    if kind == IdentifierKind.DOI:
        return normalize_doi(value)
    if kind == IdentifierKind.ARXIV:
        return normalize_arxiv_id(value)
    if kind == IdentifierKind.PMCID:
        return normalize_pmcid(value)
    if kind == IdentifierKind.PMID:
        return normalize_pmid(value)
    return None


def normalize_arxiv_id(value: str | None) -> str | None:
    text = (value or "").strip()
    if not text:
        return None
    parsed = urlparse(text)
    if parsed.scheme in {"http", "https"} and "arxiv.org" in parsed.netloc.lower():
        return _arxiv_from_path(parsed.path)
    raw_match = ARXIV_RAW_RE.match(text)
    if raw_match:
        version = (raw_match.group(2) or "").lower()
        return f"{raw_match.group(1).lower()}{version}"
    match = ARXIV_ABS_RE.search(text)
    if not match:
        return None
    version = (match.group(2) or "").lower()
    return f"{match.group(1).lower()}{version}"


def _arxiv_from_path(path: str) -> str | None:
    match = ARXIV_PATH_RE.match(path or "")
    if not match:
        return None
    version = (match.group(2) or "").lower()
    return f"{match.group(1).lower()}{version}"


def normalize_pmcid(value: str | None) -> str | None:
    text = (value or "").strip()
    if not text:
        return None
    parsed = urlparse(text)
    if parsed.scheme in {"http", "https"} and "ncbi.nlm.nih.gov" in parsed.netloc.lower():
        return _first_match(PMCID_RE, parsed.path)
    return _first_match(PMCID_RE, text)


def normalize_pmid(value: str | None) -> str | None:
    text = (value or "").strip()
    if not text:
        return None
    parsed = urlparse(text)
    if parsed.scheme in {"http", "https"} and "pubmed.ncbi.nlm.nih.gov" in parsed.netloc.lower():
        match = PUBMED_PATH_RE.match(parsed.path or "")
        if not match:
            return None
        return match.group(1)
    return None


def _first_match(pattern: re.Pattern[str], value: str) -> str | None:
    match = pattern.search(value)
    if not match:
        return None
    return match.group(1).upper()
