"""URL normalizer for Avatar execution plans (Phase A)."""

from __future__ import annotations

import difflib
import re
from urllib.parse import urlparse

_DOMAIN_RE = re.compile(
    r"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,63}$"
)
_DOMAIN_IN_TEXT_RE = re.compile(
    r"\b(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,63}\b"
)
_URL_IN_TEXT_RE = re.compile(r"https?://[^\s<>\"']+", re.IGNORECASE)
_KNOWN_DOMAIN_TYPOS: dict[str, str] = {
    "saucers.md": "stauceni.md",
    "saucer.md": "stauceni.md",
    "stauсeni.md": "stauceni.md",
    "stauzeni.md": "stauceni.md",
}
_STAUCENI_FUZZY_TARGET = "stauceni"
_BLOCKED_SCHEMES = frozenset(
    {
        "javascript",
        "file",
        "data",
        "vbscript",
        "about",
        "blob",
    }
)


def normalize_avatar_url(raw: str | None) -> str | None:
    """
    Normalize user or planner URL input for browser/fetch handlers.

    Examples:
        stauceni.md -> https://stauceni.md/
        https://stauceni.md -> https://stauceni.md/
    """
    value = str(raw or "").strip().rstrip(".,;)")
    if not value:
        return None

    lower = value.lower()
    if "://" in lower:
        parsed = urlparse(value)
        scheme = (parsed.scheme or "").lower()
        if scheme in _BLOCKED_SCHEMES:
            return None
        if scheme not in {"http", "https"}:
            return None
        host = (parsed.hostname or "").strip()
        if not host:
            return None
        path = parsed.path or ""
        if not path or path == "/":
            return f"{scheme}://{host}/"
        return value

    if lower.startswith("//"):
        return normalize_avatar_url(f"https:{value}")

    host = value.split("/", 1)[0].strip().lower()
    if not _DOMAIN_RE.fullmatch(host):
        return None
    return f"https://{host}/"


def suggest_domain_correction(raw: str) -> str:
    """Map common NL typos (e.g. saucers.md) to known acceptance domains."""
    value = str(raw or "").strip().rstrip(".,;)").lower()
    if not value:
        return raw
    if value in _KNOWN_DOMAIN_TYPOS:
        return _KNOWN_DOMAIN_TYPOS[value]
    host = value.split("/", 1)[0]
    base = host.rsplit(".", 1)[0] if "." in host else host
    if difflib.SequenceMatcher(None, base, _STAUCENI_FUZZY_TARGET).ratio() >= 0.75:
        return "stauceni.md"
    return raw


def extract_normalized_url_from_text(text: str, *, correct_typos: bool = True) -> str | None:
    """Extract http(s) or domain-only mention from NL and normalize to https URL."""
    raw_text = str(text or "")
    url_match = _URL_IN_TEXT_RE.search(raw_text)
    if url_match:
        return normalize_avatar_url(url_match.group(0).rstrip(".,;)"))
    domain_match = _DOMAIN_IN_TEXT_RE.search(raw_text)
    if not domain_match:
        return None
    domain = domain_match.group(0)
    if correct_typos:
        domain = suggest_domain_correction(domain)
    return normalize_avatar_url(domain)
