"""URL detector.

Detects URLs that may carry PII in query strings, paths, or credentials
(e.g. embedded username:password, user-ID path segments).

We intentionally flag *all* URLs so callers can decide whether to redact;
conflict resolution at the redaction layer will prefer higher-priority types
(e.g. EMAIL found inside a mailto: URL stays EMAIL).
"""
import re
from typing import Dict, List, Union

from upf.config import UPFConfig

# Full URL: scheme://[user:pass@]host[:port][/path][?query][#fragment]
# Also matches bare www. links and mailto: addresses.
_URL_RE = re.compile(
    r"""
    (?:
        # mailto: (no slashes)
        mailto:[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}
    |
        # Scheme-prefixed URLs with //
        (?:https?|ftp|sftp|ftps|ssh|git|svn|rtsp|ws|wss)://
        (?:[A-Za-z0-9._~:@!$&'()*+,;=%-]+@)?   # optional user:pass@
        [A-Za-z0-9.\-]+                          # host
        (?::\d{1,5})?                            # optional port
        (?:/[^\s"'<>(){}|\[\]\\^`]*)?           # optional path/query/fragment
    |
        # Bare www. links (no scheme)
        \bwww\.[A-Za-z0-9.\-]+\.[A-Za-z]{2,}
        (?:/[^\s"'<>(){}|\[\]\\^`]*)?
    )
    """,
    re.VERBOSE | re.IGNORECASE,
)


def detect_url_entities(text: str, config: UPFConfig) -> List[Dict[str, Union[int, str]]]:
    """Detect URLs in *text*.

    Gated by ``config.redact_urls`` (defaults to ``True``).
    """
    if not getattr(config, "redact_urls", True):
        return []

    findings: List[Dict[str, Union[int, str]]] = []
    for m in _URL_RE.finditer(text):
        findings.append({
            "type": "URL",
            "start": m.start(),
            "end": m.end(),
            "text": m.group(),
        })
    return findings
