"""HTML rendering helpers for log entries."""

from __future__ import annotations

import re
import time
from datetime import UTC, datetime
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from blackbox.models import LogEntry

FILTER_PRESETS: dict[str, set[str] | None] = {
    "all": None,
    "compact": None,
    "important": {"status", "assistant", "error", "info"},
    "errors": {"error"},
}

SKIP_LEVELS = {
    "delta",
    "stream",
    "block_stop",
    "block_start",
    "thinking_delta",
    "tool_start",
}


def fmt_time(ts: float) -> str:
    return datetime.fromtimestamp(ts, tz=UTC).strftime("%H:%M:%S")


def fmt_duration(started: float, finished: float | None) -> str:
    end = finished or time.time()
    secs = int(end - started)
    if secs < 0:
        return "0s"
    if secs < 60:
        return f"{secs}s"
    mins, secs = divmod(secs, 60)
    if mins < 60:
        return f"{mins}m{secs:02d}s"
    hrs, mins = divmod(mins, 60)
    return f"{hrs}h{mins:02d}m"


def fmt_relative(ts: float) -> str:
    delta = time.time() - ts
    if delta < 60:
        return "just now"
    if delta < 3600:
        return f"{int(delta / 60)}m ago"
    if delta < 86400:
        return f"{int(delta / 3600)}h ago"
    return f"{int(delta / 86400)}d ago"


def passes_filter(
    entry: LogEntry,
    filter_name: str,
    allowed: set[str] | None,
) -> bool:
    stripped = entry.message.strip()
    if not stripped:
        return False
    if filter_name == "all":
        return True
    if entry.level in SKIP_LEVELS:
        return False
    if allowed is not None and entry.level not in allowed:
        return False
    return not (entry.level == "assistant" and stripped == "(thinking)")


def esc(text: str) -> str:
    return text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace("\n", "<br>")


BOLD_RE = re.compile(r"\*\*(.+?)\*\*")


def esc_md(text: str) -> str:
    escaped = esc(text)
    return BOLD_RE.sub(r'<strong class="text-white">\1</strong>', escaped)


def shorten_paths(text: str) -> str:
    text = re.sub(r"/(?:private/)?tmp/[^\s\"']+/?", "", text)
    return text


SOURCE_CLASSES = {
    "claude": "bg-blue-500",
    "user": "bg-green-500",
    "system": "bg-surface-700",
}

SOURCE_LABELS = {
    "claude": "CLU",
    "user": "USR",
    "system": "SYS",
}


def tool_call_html(preview: str) -> str:
    shortened = shorten_paths(preview)
    lines = shortened.split("\n")
    if len(lines) <= 3:
        return f'<span class="text-gray-500">{esc(shortened)}</span>'
    summary = esc(lines[0])
    rest = esc("\n".join(lines[1:]))
    return (
        f'<span class="text-gray-500">{summary}'
        f'<details class="inline"><summary class="cursor-pointer'
        f' text-gray-600 text-xs ml-1">+{len(lines) - 1}'
        f" lines</summary>"
        f'<pre class="text-xs mt-1 text-gray-600'
        f' whitespace-pre-wrap">{rest}</pre>'
        f"</details></span>"
    )


def render_log_html(entry: LogEntry) -> str:
    ts = fmt_time(entry.timestamp)
    src_cls = SOURCE_CLASSES.get(entry.source, "bg-gray-600")
    src_label = SOURCE_LABELS.get(entry.source, entry.source[:3].upper())

    if entry.level == "tool_call":
        tool = entry.data.get("tool", "tool")
        preview = entry.data.get("input_preview", entry.message)
        badge_cls = "bg-amber-500"
        badge_label = esc(tool[:12])
    elif entry.level == "tool_result":
        badge_cls = "bg-gray-700"
        badge_label = "RES"
    else:
        badge_cls = src_cls
        badge_label = src_label

    level = entry.level
    is_thinking = level == "assistant" and entry.message.strip() == "(thinking)"

    if entry.source == "user" and level == "info":
        msg = f'<span class="text-green-300 font-medium">{esc_md(entry.message)}</span>'
    elif level == "tool_call":
        preview = entry.data.get("input_preview", "")
        msg = tool_call_html(preview)
    elif level == "tool_result":
        text = entry.message[:500]
        if len(entry.message) > 500:
            text += "..."
        msg = f'<span class="text-gray-500">{esc(shorten_paths(text))}</span>'
    elif level == "assistant":
        if is_thinking:
            msg = f'<span class="text-gray-500 italic">{esc(entry.message)}</span>'
        else:
            msg = f'<span class="text-gray-100">{esc_md(entry.message)}</span>'
    elif level == "error":
        msg = f'<span class="text-red-400 font-medium">{esc(entry.message)}</span>'
    else:
        msg = f'<span class="text-gray-300">{esc(entry.message)}</span>'

    extra_div_classes = " border-t border-surface-800 mt-2 pt-1" if is_thinking else ""

    is_tool = level in {"tool_call", "tool_result"}
    opacity = " opacity-60" if is_tool else ""
    indent = " pl-4" if is_tool else ""

    return (
        f'<div class="flex gap-2 py-0.5 px-2 hover:bg-surface-800/50'
        f" rounded group{extra_div_classes}{opacity}{indent}"
        f'">'
        f'<span class="text-gray-600 shrink-0 text-xs'
        f' leading-5">{ts}</span>'
        f'<span class="{badge_cls} text-white px-1.5 rounded'
        f' text-xs leading-5 font-mono shrink-0 self-start">'
        f"{badge_label}</span>"
        f'<span class="leading-5 break-all">{msg}</span>'
        f"</div>"
    )
