# retoor <retoor@molodetz.nl>

from __future__ import annotations

import html
import json
import re

import httpx

SCRIPT_STYLE = re.compile(r"<(script|style)[^>]*>.*?</\1>", re.IGNORECASE | re.DOTALL)
ANCHOR = re.compile(
    r"<a\b[^>]*?\bhref\s*=\s*(?:\"([^\"]*)\"|'([^']*)'|([^\s>]+))[^>]*>(.*?)</a>",
    re.IGNORECASE | re.DOTALL,
)
TAG = re.compile(r"<[^>]+>")
BLANK_LINES = re.compile(r"\n\s*\n\s*\n+")
TRAILING_SPACE = re.compile(r"[ \t]+\n")
SKIP_HREF_PREFIXES = ("#", "javascript:")

def normalize_newlines(text: str) -> str:
    if not text or not isinstance(text, str):
        return "" if text is None else str(text)
    value = text
    while "\\\\n" in value:
        value = value.replace("\\\\n", "\\n")
    while "\\\\t" in value:
        value = value.replace("\\\\t", "\\t")
    escaped_n = value.count("\\n")
    real_n = value.count("\n")
    if escaped_n > real_n:
        value = value.replace("\\n", "\n")
    escaped_t = value.count("\\t")
    real_t = value.count("\t")
    if escaped_t > real_t:
        value = value.replace("\\t", "\t")
    return value


HIDDEN = "[hidden]"
REDACT_FIELD_KEYS = frozenset(
    {
        "gateway_upstream_url",
        "gateway_model",
        "gateway_vision_url",
        "gateway_vision_model",
    }
)
REDACT_STAT_LABELS = frozenset({"Model"})


def redact_backend(obj):
    if isinstance(obj, dict):
        if "value" in obj and obj.get("key") in REDACT_FIELD_KEYS:
            obj["value"] = HIDDEN
        if "value" in obj and obj.get("label") in REDACT_STAT_LABELS:
            obj["value"] = HIDDEN
        for value in obj.values():
            redact_backend(value)
    elif isinstance(obj, list):
        for item in obj:
            redact_backend(item)
    return obj


def _render_anchor(match: re.Match[str]) -> str:
    href = (match.group(1) or match.group(2) or match.group(3) or "").strip()
    text = html.unescape(TAG.sub(" ", match.group(4))).strip()
    if not href or href.startswith(SKIP_HREF_PREFIXES):
        return text
    if not text:
        return href
    return f"{text} ({href})"


def html_to_text(markup: str) -> str:
    without_blocks = SCRIPT_STYLE.sub(" ", markup)
    with_links = ANCHOR.sub(_render_anchor, without_blocks)
    stripped = TAG.sub("\n", with_links)
    unescaped = html.unescape(stripped)
    collapsed = TRAILING_SPACE.sub("\n", unescaped)
    collapsed = BLANK_LINES.sub("\n\n", collapsed)
    lines = [line.strip() for line in collapsed.splitlines()]
    return "\n".join(line for line in lines if line).strip()


def truncate(body: str, max_chars: int) -> str:
    if len(body) <= max_chars:
        return body
    return body[:max_chars] + f"\n...[truncated {len(body) - max_chars} chars]"


def format_response(response: httpx.Response) -> str:
    content_type = response.headers.get("content-type", "")
    summary = {"status": response.status_code, "url": str(response.url)}

    if "application/json" in content_type:
        try:
            summary["body"] = redact_backend(response.json())
        except ValueError:
            summary["body"] = response.text
        return json.dumps(summary, ensure_ascii=False)

    if (
        content_type.startswith("text/")
        or "html" in content_type
        or "xml" in content_type
    ):
        summary["body"] = html_to_text(response.text)
        return json.dumps(summary, ensure_ascii=False)

    summary["body"] = f"binary response ({len(response.content)} bytes, {content_type})"
    return json.dumps(summary, ensure_ascii=False)
