"""Genera el mockup vN del Dashboard Bento con el gráfico de Ventas suavizado.
Uso: python3 gen_chart.py <dir_mockups> <version> <ventana_hero>
Lee bento-dashboard-map.html (v1) y escribe bento-dashboard-map-v<version>.html."""
import re, sys, pathlib
sp, version, hero_win = pathlib.Path(sys.argv[1]), sys.argv[2], int(sys.argv[3])
v1 = (sp / "bento-dashboard-map.html").read_text(encoding="utf-8")

svg_old = re.search(r'<svg class="tile__sparkline".*?</svg>', v1, re.S).group(0)
polys = re.findall(r'<polyline points="([^"]+)"', svg_old)
def pts(s): return [tuple(map(float, p.split(","))) for p in s.split()]
expected = pts(polys[0]); real = pts(polys[1]); n = len(real)

W, H, PAD_T, PAD_B, PLOT_R = 326.0, 120.0, 10.0, 10.0, 318.0
def sx(i): return round(i / (n - 1) * PLOT_R, 1)
def sy(y72): return round(PAD_T + (y72 / 72.0) * (H - PAD_T - PAD_B), 1)

def smooth(vals, win):
    if win <= 1: return list(vals)
    half = win // 2
    out = [sum(vals[max(0, i-half):i+half+1]) / len(vals[max(0, i-half):i+half+1]) for i in range(len(vals))]
    for k in range(min(3, len(vals))):      # anclaje gradual hacia el valor real de hoy
        i = len(vals) - 1 - k; w = 1 - k / 3
        out[i] = w * vals[i] + (1 - w) * out[i]
    return out

def monotone_path(xs, ys):
    k = len(xs)
    d = [(ys[i+1]-ys[i]) / (xs[i+1]-xs[i]) for i in range(k-1)]
    m = [0.0]*k; m[0], m[-1] = d[0], d[-1]
    for i in range(1, k-1):
        if d[i-1]*d[i] <= 0: m[i] = 0.0
        else:
            h0, h1 = xs[i]-xs[i-1], xs[i+1]-xs[i]
            m[i] = 3*(h0+h1) / ((2*h1+h0)/d[i-1] + (h1+2*h0)/d[i])
    parts = [f"M{xs[0]},{ys[0]}"]
    for i in range(k-1):
        h = xs[i+1]-xs[i]
        parts.append(f"C{xs[i]+h/3:.1f},{ys[i]+m[i]*h/3:.1f} {xs[i+1]-h/3:.1f},{ys[i+1]-m[i+1]*h/3:.1f} {xs[i+1]},{ys[i+1]}")
    return " ".join(parts)

xs = [sx(i) for i in range(n)]
TICKS = [(6, "4 may"), (13, "11 may"), (20, "18 may"), (27, "25 may")]   # lunes
def chart(win, gid):
    rs = smooth([y for (_, y) in real], win); es = [y for (_, y) in expected]
    lo, hi = min(rs + es), max(rs + es); pad = (hi - lo) * 0.06
    def fit(v): return round(PAD_T + (v - (lo - pad)) / ((hi + pad) - (lo - pad)) * (H - PAD_T - PAD_B), 1)
    ry = [fit(v) for v in rs]; ey = [fit(v) for v in es]
    line = monotone_path(xs, ry); area = f"{line} L{xs[-1]},{H} L{xs[0]},{H} Z"; exp = monotone_path(xs, ey)
    grid = "".join(f'<line x1="{sx(i)}" y1="0" x2="{sx(i)}" y2="{H}" class="chart__grid"/>' for i, _ in TICKS)
    labels = "".join(f'<span style="left:{sx(i)/W*100:.1f}%;">{t}</span>' for i, t in TICKS)
    dx, dy = xs[-1], ry[-1]
    svg = (f'<svg viewBox="0 0 {W:g} {H:g}" preserveAspectRatio="none" aria-label="Ventas de los últimos 30 días frente a lo esperado">'
           f'<defs><linearGradient id="grad-{gid}" x1="0" y1="0" x2="0" y2="1"><stop offset="0" class="chart__grad-a"/><stop offset="1" class="chart__grad-b"/></linearGradient></defs>'
           f'{grid}<path d="{area}" fill="url(#grad-{gid})"/><path d="{exp}" class="chart__expected"/><path d="{line}" class="chart__line"/>'
           f'<circle cx="{dx}" cy="{dy}" r="9" class="chart__halo"/><circle cx="{dx}" cy="{dy}" r="4" class="chart__dot"/></svg>')
    tip = (f'<div class="chart__tip" style="right:calc(100% - {dx/W*100:.1f}% + 16px);top:{dy-27:.0f}px;">'
           f'<span class="chart__tip-date">Hoy · 27 may</span><span class="chart__tip-value">2.957 €</span></div>')
    return f'<div class="chart">{svg}{tip}<div class="chart__axis">{labels}</div></div>'

legend = ('<div class="tile__row" style="gap:14px;">'
          '<span class="tile__legend"><span class="tile__dot" style="background:var(--app-chart-accent);"></span>venta real · 30 días</span>'
          '<span class="tile__legend"><span class="tile__dot" style="background:var(--text-secondary);"></span>esperado</span></div>')

css = """
/* ---- Gráfico de línea (referencia del usuario) ----------------------- */
.chart { position: relative; }
.chart svg { display: block; width: 100%; height: 120px; overflow: visible; }
.chart__grid { stroke: var(--border-default); stroke-width: 1; stroke-dasharray: 3 5; }
.chart__line { fill: none; stroke: var(--app-chart-accent); stroke-width: 2; stroke-linecap: round; }
.chart__expected { fill: none; stroke: var(--text-secondary); stroke-width: 1.25; opacity: 0.8; }
.chart__grad-a { stop-color: var(--app-chart-accent); stop-opacity: 0.32; }
.chart__grad-b { stop-color: var(--app-chart-accent); stop-opacity: 0; }
.chart__halo { fill: var(--app-chart-accent); opacity: 0.25; }
.chart__dot { fill: var(--app-chart-accent); stroke: var(--bg-surface-raised); stroke-width: 2; }
.chart__axis { position: relative; height: 18px; margin-top: 6px; border-top: 1px solid var(--border-subtle); padding-top: 4px; }
.chart__axis span { position: absolute; transform: translateX(-50%); font-size: 13px; line-height: 18px; font-weight: 300; color: var(--app-text-support); white-space: nowrap; }
.chart__tip { position: absolute; display: flex; flex-direction: column; gap: 2px; padding: 8px 12px; border-radius: var(--radius-sm); background: var(--app-tip-bg); border: 1px solid var(--border-default); white-space: nowrap; }
.chart__tip-date { font-size: 12px; line-height: 16px; font-weight: 300; color: var(--app-text-support); }
.chart__tip-value { font-size: 16px; line-height: 20px; font-weight: 400; color: var(--text-primary); }
:root, :root[data-theme="tpv-dark"] { --app-tip-bg: var(--bg-surface-highlight); }
:root[data-theme="light"], :root[data-theme="brand"] { --app-tip-bg: var(--bg-surface); }
/* ---- Sección de variantes (solo mockup) ------------------------------- */
.variants { max-width: 1240px; margin: 0 auto; padding: 0 16px 140px; }
.variants h2 { font: 400 16px/24px var(--font-sans); letter-spacing: 1px; text-transform: uppercase; color: var(--text-primary); margin: 0 0 12px; }
.variants__row { display: flex; flex-wrap: wrap; gap: 24px; justify-content: center; }
.variant { width: 390px; }
.variant .tile { min-height: 0; }
"""

def card(letter, title, note, ch):
    return (f'<section class="variant"><p class="phone__label">{letter} · {title}</p><div class="tile tile--hero" style="--i:0;">'
            f'<div class="tile__head"><span class="ds" data-ds="Icon" data-props=\'{{"name": "menu_bar_income", "size": 20}}\'></span><p class="tile__label">Ventas</p></div>'
            f'<div class="tile__figure"><span>2.957 €</span></div><p class="tile__note tile__note--ok">+15 % sobre lo esperado (2.562 €) · buen día</p>'
            f'{ch}{legend}<p class="tile__note" style="font-weight:300;">{note}</p></div></section>')

VARIANTS = [("A", "diario exacto", 1, "La curva pasa por el valor real de cada día. Nerviosa, sin inventar nada."),
            ("B", "tendencia de 3 días", 3, "Media móvil de 3 días. El punto de hoy se ancla al valor real."),
            ("C", "tendencia de 7 días", 7, "Media móvil semanal. La más parecida a la referencia; pierde los picos de un día.")]

out = v1.replace(svg_old, chart(hero_win, "hero"), 1)
old_legend = re.search(r'<div class="tile__row" style="gap:14px;">\s*<span class="tile__legend"><span class="tile__dot" style="background:var\(--app-chart-ink\);.*?</div>', out, re.S).group(0)
out = out.replace(old_legend, legend, 1).replace("</style>", css + "</style>", 1)
out = out.replace("<title>Mapa Bento · Dashboard Pulso</title>", f"<title>Mapa Bento v{version} · gráfico de Ventas</title>", 1)
variants = ('<section class="variants"><h2>Variantes del gráfico de Ventas</h2><div class="variants__row">'
            + "".join(card(l, t, note, chart(w, l.lower())) for (l, t, w, note) in VARIANTS) + '</div></section>')
out = out.replace('<script src="http://localhost:8765/vendor/react.production.min.js">', variants + '\n<script src="http://localhost:8765/vendor/react.production.min.js">', 1)
target = sp / f"bento-dashboard-map-v{version}.html"
target.write_text(out, encoding="utf-8")
print("escrito", target.name, len(out), "bytes · hero con ventana", hero_win)
