"""Embedded browser UI state — history, tabs, panel layout."""

from __future__ import annotations

from datetime import datetime, timezone
from typing import Any
from urllib.parse import urlparse

BROWSER_UI_CONTEXT = "embedded_browser"
MAX_URL_HISTORY = 128
MAX_VISIT_LOG = 512
MAX_TABS = 12


def _utcnow_iso() -> str:
    return datetime.now(timezone.utc).replace(tzinfo=None).isoformat(timespec="seconds")


def _is_safe_url(url: str) -> bool:
    try:
        parsed = urlparse(url.strip())
    except Exception:
        return False
    if parsed.scheme not in ("http", "https"):
        return False
    if parsed.username or parsed.password:
        return False
    return bool(parsed.netloc)


def _hostname(url: str) -> str:
    try:
        return urlparse(url).hostname or url
    except Exception:
        return url


def empty_browser_state() -> dict[str, Any]:
    return {
        "url_history": [],
        "visits": [],
        "tabs": [],
        "active_tab_id": None,
        "minimized": False,
        "rect": None,
        "minimized_rect": None,
    }


def _parse_rect(raw: dict | None, *, default_w: float, default_h: float) -> dict[str, float] | None:
    if raw is None or not isinstance(raw, dict):
        return None
    try:
        return {
            "x": float(raw.get("x", 0)),
            "y": float(raw.get("y", 0)),
            "w": float(raw.get("w", default_w)),
            "h": float(raw.get("h", default_h)),
        }
    except (TypeError, ValueError):
        return None


def parse_browser_state(raw: dict | None) -> dict[str, Any]:
    base = empty_browser_state()
    if not raw or not isinstance(raw, dict):
        return base

    url_history = [
        u for u in raw.get("url_history") or []
        if isinstance(u, str) and _is_safe_url(u)
    ][:MAX_URL_HISTORY]

    visits: list[dict[str, str]] = []
    for item in raw.get("visits") or []:
        if not isinstance(item, dict):
            continue
        url = item.get("url")
        if not isinstance(url, str) or not _is_safe_url(url):
            continue
        visits.append({
            "url": url,
            "title": str(item.get("title") or _hostname(url))[:200],
            "at": str(item.get("at") or _utcnow_iso()),
        })
    visits = visits[:MAX_VISIT_LOG]

    tabs: list[dict[str, Any]] = []
    for item in raw.get("tabs") or []:
        if not isinstance(item, dict):
            continue
        tab_id = item.get("id")
        url = item.get("url")
        if not isinstance(tab_id, str) or not tab_id.strip():
            continue
        if not isinstance(url, str):
            continue
        if url.strip() and not _is_safe_url(url):
            continue
        if url.strip():
            stack = [
                u for u in item.get("stack") or [url]
                if isinstance(u, str) and _is_safe_url(u)
            ] or [url]
            stack_index = item.get("stack_index", len(stack) - 1)
            if not isinstance(stack_index, int):
                stack_index = len(stack) - 1
            stack_index = max(0, min(stack_index, len(stack) - 1))
        else:
            stack = []
            stack_index = -1
        tabs.append({
            "id": tab_id.strip()[:64],
            "url": url.strip(),
            "title": str(item.get("title") or (_hostname(url) if url.strip() else "新标签"))[:200],
            "stack": stack[-64:],
            "stack_index": stack_index,
        })
    tabs = tabs[:MAX_TABS]

    active_tab_id = raw.get("active_tab_id")
    if not isinstance(active_tab_id, str) or not any(t["id"] == active_tab_id for t in tabs):
        active_tab_id = tabs[0]["id"] if tabs else None

    rect = _parse_rect(raw.get("rect"), default_w=960, default_h=640)
    minimized_rect = _parse_rect(raw.get("minimized_rect"), default_w=320, default_h=52)

    return {
        "url_history": url_history,
        "visits": visits,
        "tabs": tabs,
        "active_tab_id": active_tab_id,
        "minimized": bool(raw.get("minimized")),
        "rect": rect,
        "minimized_rect": minimized_rect,
    }


def merge_browser_state(current: dict[str, Any], incoming: dict[str, Any]) -> dict[str, Any]:
    parsed = parse_browser_state({**current, **incoming})
    if incoming.get("url_history") is not None:
        parsed["url_history"] = parse_browser_state({"url_history": incoming["url_history"]})["url_history"]
    if incoming.get("visits") is not None:
        parsed["visits"] = parse_browser_state({"visits": incoming["visits"]})["visits"]
    return parsed


def record_visit(state: dict[str, Any], url: str, title: str | None = None) -> dict[str, Any]:
    if not _is_safe_url(url):
        return state
    next_state = parse_browser_state(state)
    hist = [url] + [u for u in next_state["url_history"] if u != url]
    next_state["url_history"] = hist[:MAX_URL_HISTORY]
    visit = {
        "url": url,
        "title": (title or _hostname(url))[:200],
        "at": _utcnow_iso(),
    }
    visits = [visit] + next_state["visits"]
    next_state["visits"] = visits[:MAX_VISIT_LOG]
    return next_state
