"""Finding-Annotator — pro Befund ein PNG mit Marker.

Erzeugt für die Audit-Mail einen visuellen Beweis pro Finding:
roter Rand um das verletzende Element + Label-Banner darüber.

Aktuell unterstützte Annotation-Typen:
  - "tap_target_too_small"   B1 Mobile-Reachability — markiert den
                              Footer-Anchor mit Größenanforderung
  - "slug_404"               B16 URL-Slug-Drift — Screenshot des
                              404-Slugs mit "Standard-Slug 404"
  - "missing_link_in_footer" B13 Widerruf — Footer-Screenshot mit
                              "→ Widerruf-Link erwartet, fehlt"

Output: bytes (PNG). Best-Effort: Fehler beim Rendern werfen nicht,
sondern returnen leere bytes (caller dropt das Asset).
"""

from __future__ import annotations

import base64
import logging
from typing import Any

logger = logging.getLogger(__name__)


# Banner-Style für Label oben im Bild (rot mit weißer Schrift).
_LABEL_JS = """
(label) => {
  const div = document.createElement('div');
  div.style.cssText = `
    position:fixed;top:0;left:0;right:0;z-index:2147483647;
    background:#dc2626;color:#fff;padding:14px 24px;
    font:bold 18px/1.2 -apple-system,sans-serif;
    box-shadow:0 4px 12px rgba(0,0,0,0.4);
    border-bottom:3px solid #7f1d1d;text-align:center;
  `;
  div.textContent = label;
  document.body.appendChild(div);
}
"""

# JS zum Markieren eines Elements: roter Rand + 0.4-Schatten innen.
_MARK_JS = """
(args) => {
  const sel = args.selector;
  const text = args.text;
  let el = null;
  if (sel) {
    try { el = document.querySelector(sel); } catch(e) {}
  }
  if (!el && text) {
    const all = document.querySelectorAll('a, button, [role=button]');
    for (const c of all) {
      if ((c.innerText || '').trim().toLowerCase()
            .includes(text.toLowerCase())) {
        el = c; break;
      }
    }
  }
  if (!el) return false;
  el.scrollIntoView({behavior:'instant', block:'center'});
  el.style.outline = '4px solid #dc2626';
  el.style.outlineOffset = '4px';
  el.style.boxShadow = 'inset 0 0 0 9999px rgba(220,38,38,0.15)';
  return true;
}
"""


async def annotate_url(
    url: str,
    label: str,
    selector: str | None = None,
    text_match: str | None = None,
    viewport_w: int = 1280,
    viewport_h: int = 800,
    timeout_s: float = 20.0,
) -> bytes:
    """Open `url`, mark element by selector or text-match, save PNG."""
    try:
        from playwright.async_api import async_playwright
    except Exception as e:
        logger.warning("playwright unavailable: %s", e)
        return b""

    async with async_playwright() as p:
        try:
            browser = await p.webkit.launch(headless=True)
            context = await browser.new_context(
                viewport={"width": viewport_w, "height": viewport_h},
                locale="de-DE",
            )
            page = await context.new_page()
            try:
                await page.goto(url, wait_until="domcontentloaded",
                                timeout=timeout_s * 1000)
            except Exception as e:
                logger.info("annotate_url goto failed for %s: %s",
                             url, e)
            await page.wait_for_timeout(1500)
            await page.evaluate(_LABEL_JS, label)
            if selector or text_match:
                try:
                    await page.evaluate(
                        _MARK_JS,
                        {"selector": selector or "",
                         "text": text_match or ""},
                    )
                except Exception as e:
                    logger.info("annotate mark failed: %s", e)
            await page.wait_for_timeout(500)
            png = await page.screenshot(full_page=False, type="png")
            await context.close()
            await browser.close()
            return png
        except Exception as e:
            logger.warning("annotate_url failed: %s", e)
            return b""


async def annotate_findings(
    findings: list[dict],
    home_url: str,
) -> list[dict[str, Any]]:
    """Per finding produce a PNG. Returns list of {filename, png_b64}.

    Supported finding shapes:
      - {check_id: 'COOKIE-CONSENT-UX-001', mobile_playwright:
         {anchor_text: '...'}}
      - {check_id: 'URL-SLUG-DRIFT-001', alt_slugs_404: [...],
         doc_type: '...', source_url: '...'}  (Stufe-1: nimmt source_url
         aus state, hier optional)
      - {check_id: 'WIDERRUF-REACH-001'} → Footer-Screenshot der
         Homepage mit "→ Widerruf-Link fehlt"

    Skip silently if a finding doesn't match a supported shape.
    """
    out: list[dict[str, Any]] = []
    for f in findings:
        cid = (f.get("check_id") or "").upper()
        png = b""
        fname = ""
        if cid == "COOKIE-CONSENT-UX-001":
            mob = f.get("mobile_playwright") or {}
            anchor_text = mob.get("anchor_text") or ""
            if anchor_text:
                tp = mob.get("tap_target_px") or {}
                label = (
                    f"B1 — Tap-Target {tp.get('w','?')}×{tp.get('h','?')} "
                    "px (Anforderung ≥ 44×44)"
                )
                png = await annotate_url(
                    home_url, label, text_match=anchor_text,
                )
                fname = f"finding-tap-target.png"
        elif cid == "URL-SLUG-DRIFT-001":
            alts = f.get("alt_slugs_404") or []
            if alts:
                # Pick first 404-slug + screenshot the 404 page
                doc_type = f.get("doc_type") or "x"
                from urllib.parse import urlparse
                p = urlparse(home_url)
                origin = f"{p.scheme}://{p.netloc}"
                slug_url = f"{origin}/{alts[0]}"
                label = (
                    f"B16 — Standard-Slug 404 ({doc_type}): /{alts[0]}"
                )
                png = await annotate_url(slug_url, label)
                fname = f"finding-slug-404-{doc_type}.png"
        elif cid == "WIDERRUF-REACH-001":
            label = "B13 — Widerrufsbelehrung im Footer erwartet, fehlt"
            png = await annotate_url(
                home_url, label, selector="footer",
            )
            fname = "finding-widerruf-missing.png"

        if png and fname:
            out.append({
                "filename": fname,
                "png_b64": base64.b64encode(png).decode("ascii"),
            })
    return out
