"""Plain-text and URL hardening for dashboard JSON (shell renders with textContent)."""

from __future__ import annotations

import re
from urllib.parse import urlparse

_CTRL_RE = re.compile(r"[\x00-\x08\x0b\x0c\x0e-\x1f]")


def safe_clip(s: str, max_len: int = 4000) -> str:
    t = sanitize_plain_text(s, max_len=max_len)
    if len(t) > max_len:
        return t[: max_len - 1] + "…"
    return t


def sanitize_plain_text(s: str | None, max_len: int = 8000) -> str:
    """Remove control chars; keep newlines for pre-wrap where allowed."""
    if s is None:
        return ""
    if not isinstance(s, str):
        s = str(s)
    s = _CTRL_RE.sub("", s.replace("\r\n", "\n").replace("\r", "\n"))
    if len(s) > max_len:
        s = s[:max_len] + "…"
    return s


def safe_http_url(raw: str | None, max_len: int = 2048) -> str | None:
    if not isinstance(raw, str):
        return None
    u = raw.strip()
    if not u or len(u) > max_len:
        return None
    try:
        p = urlparse(u)
    except Exception:
        return None
    if p.scheme not in ("http", "https"):
        return None
    if not p.netloc:
        return None
    return u
