"""Generate docs/Promo_Tool_Presentation.pptx — walkthrough deck for CMs +
management to introduce the Promo Tool. Each slide has a title, bullet
explanation, and a screenshot placeholder rectangle the user fills in
manually after running the app.

Run: py build_promo_tool_deck.py
Requires: python-pptx  (pip install python-pptx --break-system-packages)
"""
from __future__ import annotations

from pathlib import Path

from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.shapes import MSO_SHAPE
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.oxml.ns import qn
from lxml import etree


# ---------------- Brand palette ----------------
NAVY    = RGBColor(0x0C, 0x23, 0x40)
NAVY_LT = RGBColor(0x1F, 0x3A, 0x5F)
ACCENT  = RGBColor(0xE8, 0x73, 0x4A)
BG      = RGBColor(0xF7, 0xF8, 0xFA)
WHITE   = RGBColor(0xFF, 0xFF, 0xFF)
TEXT    = RGBColor(0x1F, 0x29, 0x37)
GRAY    = RGBColor(0x6B, 0x72, 0x80)
GRAY_LT = RGBColor(0xD1, 0xD5, 0xDB)
GREEN   = RGBColor(0x10, 0xB9, 0x81)


# ---------------- Helpers ----------------
def set_solid_fill(shape, rgb: RGBColor):
    shape.fill.solid()
    shape.fill.fore_color.rgb = rgb
    shape.line.fill.background()


def set_dashed_border(shape, rgb: RGBColor):
    shape.line.color.rgb = rgb
    shape.line.width = Pt(1.5)
    # python-pptx doesn't expose dash style; patch the XML
    ln = shape.line._get_or_add_ln()
    prstDash = etree.SubElement(ln, qn("a:prstDash"))
    prstDash.set("val", "dash")


def add_textbox(slide, left, top, width, height, text, *, size=14,
                bold=False, color=TEXT, align=PP_ALIGN.LEFT,
                anchor=MSO_ANCHOR.TOP, font="Calibri"):
    tb = slide.shapes.add_textbox(left, top, width, height)
    tf = tb.text_frame
    tf.word_wrap = True
    tf.vertical_anchor = anchor
    tf.margin_left = tf.margin_right = Emu(0)
    tf.margin_top = tf.margin_bottom = Emu(0)
    if isinstance(text, str):
        text = [text]
    for i, line in enumerate(text):
        p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
        p.alignment = align
        r = p.add_run()
        r.text = line
        r.font.name = font
        r.font.size = Pt(size)
        r.font.bold = bold
        r.font.color.rgb = color
    return tb


def add_bullets(slide, left, top, width, height, bullets,
                size=16, color=TEXT, gap=8):
    tb = slide.shapes.add_textbox(left, top, width, height)
    tf = tb.text_frame
    tf.word_wrap = True
    tf.margin_left = tf.margin_right = Emu(0)
    for i, b in enumerate(bullets):
        p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
        p.space_after = Pt(gap)
        # Bullet char as prefix
        r = p.add_run()
        r.text = "●  "
        r.font.name = "Calibri"
        r.font.size = Pt(size)
        r.font.color.rgb = ACCENT
        r.font.bold = True
        r2 = p.add_run()
        r2.text = b
        r2.font.name = "Calibri"
        r2.font.size = Pt(size)
        r2.font.color.rgb = color


def add_screenshot_placeholder(slide, left, top, width, height, label=None):
    box = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, left, top, width, height)
    box.fill.solid()
    box.fill.fore_color.rgb = WHITE
    set_dashed_border(box, GRAY_LT)
    tf = box.text_frame
    tf.word_wrap = True
    tf.vertical_anchor = MSO_ANCHOR.MIDDLE
    p = tf.paragraphs[0]
    p.alignment = PP_ALIGN.CENTER
    r = p.add_run()
    r.text = label or "📸  Screenshot here"
    r.font.name = "Calibri"
    r.font.size = Pt(14)
    r.font.color.rgb = GRAY
    return box


def add_background(slide):
    bg = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0,
                                  prs.slide_width, prs.slide_height)
    set_solid_fill(bg, BG)
    bg.shadow.inherit = False
    slide.shapes._spTree.remove(bg._element)
    slide.shapes._spTree.insert(2, bg._element)
    return bg


def add_header_bar(slide, label, idx, total):
    # Top navy bar
    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0,
                                   prs.slide_width, Inches(0.45))
    set_solid_fill(bar, NAVY)
    # Brand text left
    add_textbox(slide, Inches(0.4), Inches(0.08), Inches(6), Inches(0.3),
                "POLLEO DEMAND  ·  PROMO TOOL", size=10, bold=True,
                color=WHITE)
    # Section label center
    if label:
        add_textbox(slide, Inches(4), Inches(0.08), Inches(6), Inches(0.3),
                    label, size=10, bold=False, color=WHITE,
                    align=PP_ALIGN.CENTER)
    # Page x of N right
    add_textbox(slide, prs.slide_width - Inches(1.6), Inches(0.08),
                Inches(1.2), Inches(0.3),
                f"{idx} / {total}", size=10, color=WHITE,
                align=PP_ALIGN.RIGHT)


def add_footer(slide):
    add_textbox(slide, Inches(0.4), prs.slide_height - Inches(0.4),
                Inches(12.5), Inches(0.3),
                "Promo Tool — interni alat za planiranje akcija",
                size=9, color=GRAY)


# ---------------- Slide builders ----------------
def slide_title(prs, title, subtitle, idx, total):
    s = prs.slides.add_slide(prs.slide_layouts[6])
    add_background(s)
    # Big navy block top
    block = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0,
                                  prs.slide_width, Inches(4.2))
    set_solid_fill(block, NAVY)
    # Accent stripe
    stripe = s.shapes.add_shape(MSO_SHAPE.RECTANGLE,
                                   0, Inches(4.2),
                                   prs.slide_width, Inches(0.12))
    set_solid_fill(stripe, ACCENT)
    # Title
    add_textbox(s, Inches(0.7), Inches(1.6), Inches(12), Inches(1.6),
                title, size=44, bold=True, color=WHITE)
    add_textbox(s, Inches(0.7), Inches(3.0), Inches(12), Inches(0.6),
                subtitle, size=18, color=RGBColor(0xB8, 0xC8, 0xDE))
    # Lower section
    add_textbox(s, Inches(0.7), Inches(5.0), Inches(12), Inches(0.5),
                "Interna prezentacija", size=11, bold=True, color=ACCENT)
    add_textbox(s, Inches(0.7), Inches(5.4), Inches(12), Inches(1.5),
                ["Cilj: prezentirati alat za planiranje retail i web akcija "
                 "kategorijskim managerima i upravi.",
                 "Audience: CM tim · Direktor nabave · Uprava",
                 "Trajanje walkthrougha: cca 15 min"],
                size=14, color=TEXT)
    return s


def slide_section(prs, label, title, idx, total):
    s = prs.slides.add_slide(prs.slide_layouts[6])
    add_background(s)
    add_textbox(s, Inches(0.7), Inches(2.5), Inches(12), Inches(0.5),
                label, size=12, bold=True, color=ACCENT,
                align=PP_ALIGN.CENTER)
    add_textbox(s, Inches(0.7), Inches(3.0), Inches(12), Inches(1.5),
                title, size=36, bold=True, color=NAVY,
                align=PP_ALIGN.CENTER)
    # Decorative dash
    dash = s.shapes.add_shape(MSO_SHAPE.RECTANGLE,
                                 Inches(6.0), Inches(4.4),
                                 Inches(1.3), Inches(0.06))
    set_solid_fill(dash, ACCENT)
    return s


def slide_walkthrough(prs, section, title, bullets, screenshot_label,
                       idx, total, *, screenshot_right=True):
    s = prs.slides.add_slide(prs.slide_layouts[6])
    add_background(s)
    add_header_bar(s, section, idx, total)
    # Slide title
    add_textbox(s, Inches(0.5), Inches(0.65), Inches(12.5), Inches(0.7),
                title, size=26, bold=True, color=NAVY)
    # Layout split
    if screenshot_right:
        # bullets on left, screenshot on right
        add_bullets(s, Inches(0.5), Inches(1.7),
                    Inches(5.2), Inches(5.0), bullets, size=14)
        add_screenshot_placeholder(
            s, Inches(6.0), Inches(1.6), Inches(7.0), Inches(5.2),
            label=f"📸  {screenshot_label}",
        )
    else:
        # screenshot on left, bullets right
        add_screenshot_placeholder(
            s, Inches(0.5), Inches(1.6), Inches(7.0), Inches(5.2),
            label=f"📸  {screenshot_label}",
        )
        add_bullets(s, Inches(7.8), Inches(1.7),
                    Inches(5.2), Inches(5.0), bullets, size=14)
    add_footer(s)
    return s


def slide_flow(prs, idx, total):
    """End-to-end flow as a horizontal swimlane diagram."""
    s = prs.slides.add_slide(prs.slide_layouts[6])
    add_background(s)
    add_header_bar(s, "End-to-end workflow", idx, total)
    add_textbox(s, Inches(0.5), Inches(0.65), Inches(12.5), Inches(0.7),
                "Kako akcija putuje od ideje do potvrde",
                size=26, bold=True, color=NAVY)

    # 5 step boxes
    steps = [
        ("1.  Plan",           "CM otvori Promo Planner,\nodabere SKU-ove +\nmehaniku i discount", NAVY_LT),
        ("2.  Validate",       "NC30 check + P&L impact\n+ analog forecast\nse računaju live", ACCENT),
        ("3.  Submit",          "📤 Submit to Promo\nCalendar — prijedlog ide\ndirektoru s statusom 💡 idea", NAVY_LT),
        ("4.  Director review", "Direktor pregleda u\nPromo Calendaru,\nflagga konflikte ako ih ima", ACCENT),
        ("5.  Outcome",         "✅ Approved →\nakcija ide live;\n↩️ vraćena → CM revidira", GREEN),
    ]
    box_w = Inches(2.35)
    box_h = Inches(2.0)
    gap = Inches(0.18)
    total_w = box_w * 5 + gap * 4
    start_left = (prs.slide_width - total_w) / 2
    top = Inches(2.4)
    for i, (head, body, col) in enumerate(steps):
        left = start_left + i * (box_w + gap)
        box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE,
                                    left, top, box_w, box_h)
        set_solid_fill(box, col)
        # Box text
        tb = s.shapes.add_textbox(left, top + Inches(0.15),
                                     box_w, box_h - Inches(0.3))
        tf = tb.text_frame
        tf.word_wrap = True
        tf.margin_left = Emu(50000)
        tf.margin_right = Emu(50000)
        p1 = tf.paragraphs[0]
        p1.alignment = PP_ALIGN.CENTER
        r1 = p1.add_run()
        r1.text = head
        r1.font.bold = True
        r1.font.size = Pt(14)
        r1.font.color.rgb = WHITE
        r1.font.name = "Calibri"
        for line in body.split("\n"):
            p2 = tf.add_paragraph()
            p2.alignment = PP_ALIGN.CENTER
            r2 = p2.add_run()
            r2.text = line
            r2.font.size = Pt(10)
            r2.font.color.rgb = WHITE
            r2.font.name = "Calibri"
        # Arrow after, except last
        if i < len(steps) - 1:
            arr = s.shapes.add_shape(MSO_SHAPE.RIGHT_ARROW,
                                        left + box_w, top + box_h / 2 - Inches(0.12),
                                        gap, Inches(0.24))
            set_solid_fill(arr, GRAY_LT)

    # Bottom note
    add_textbox(s, Inches(0.5), Inches(5.4), Inches(12.5), Inches(1.5),
                ["Svaki korak je auditiran — log se vidi i u Promo Toolu i u Promo Calendaru.",
                 "Direktor ne dira tuđi sadržaj — može samo odobriti, vratiti na doradu ili acknowledge konflikt.",
                 "Komentari direktora se prenose u Promo Tool gdje ih CM vidi prije revizije."],
                size=12, color=TEXT)
    add_footer(s)
    return s


# ============================================================
# Build the deck
# ============================================================
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)

SLIDES = []  # list of (builder_callable, args) tuples we'll execute after counting

# Counted by hand so footer "x / N" is correct. Update if adding slides.
SECTIONS = []  # (idx 1-based, kind, args)

slide_specs = [
    ("title", dict(
        title="Promo Tool",
        subtitle="Alat za planiranje retail i web akcija",
    )),

    ("section", dict(
        label="01",
        title="Zašto Promo Tool",
    )),
    ("walkthrough", dict(
        section="01 · Zašto", title="Problem koji rješavamo",
        bullets=[
            "Akcije se trenutno planiraju u Excelu, bez konzistentnog formata.",
            "Nema brze provjere NC30 (najniža cijena u zadnjih 30 dana) — rizik za usklađenost.",
            "Forecast očekivane prodaje radi se ručno, najčešće “po osjećaju”.",
            "Direktor ne vidi sve prijedloge na jednom mjestu, ne zna gdje se preklapaju.",
        ],
        screenshot_label="Stari Excel proces (placeholder)",
    )),
    ("walkthrough", dict(
        section="01 · Zašto", title="Što alat donosi",
        bullets=[
            "Jedinstveno mjesto za sve prijedloge akcija (retail + web).",
            "Automatski NC30 check po SKU-u prije submita.",
            "Analogni forecast — količina i tjedni pattern izvučeni iz povijesnih akcija.",
            "P&L impact (prihod, RUC, marža) trenutno vidljiv.",
            "Direktan workflow prema direktoru nabave kroz Promo Calendar.",
        ],
        screenshot_label="Promo Tool — landing screen",
    )),

    ("section", dict(
        label="02",
        title="Pregled aplikacije",
    )),
    ("walkthrough", dict(
        section="02 · Pregled", title="Sidebar — 4 stranice",
        bullets=[
            "🛒 Promo Planner — glavna stranica za izradu prijedloga.",
            "📋 Moji prijedlozi — status svih akcija koje si poslao.",
            "🔮 Promo Forecaster — preporuka discounta i trajanja za zadani cilj.",
            "📜 Past Promotions — pretraga povijesnih kampanja.",
        ],
        screenshot_label="Sidebar nav s 4 stranice",
    )),

    ("section", dict(
        label="03",
        title="Promo Planner — korak po korak",
    )),
    ("walkthrough", dict(
        section="03 · Planner", title="Postavke akcije (sidebar)",
        bullets=[
            "Naziv akcije — slobodni tekst (npr. 'Summer Protein Sale').",
            "Source — kanal: B2C MP (retail), B2C WEB, B2B FMCG, B2B FITNESS.",
            "Type / Outcome — npr. Univerzalna · Rješavanje lagera.",
            "Period — start i end calendar week.",
            "Channels — gdje će akcija biti vidljiva.",
        ],
        screenshot_label="Sidebar s nazivom, sourceom, datumima",
    )),
    ("walkthrough", dict(
        section="03 · Planner", title="Odabir artikala",
        bullets=[
            "Filtriraj po kategoriji / sub-kategoriji / tieru (Gold/Silver/Bronze).",
            "Multi-select SKU-ova — dodaješ jedan ili više u koš akcije.",
            "Po SKU-u se vidi cijena, MP zaliha, recent uplift, povijesne akcije.",
        ],
        screenshot_label="SKU picker s filtrima",
    )),
    ("walkthrough", dict(
        section="03 · Planner", title="🎟️ Mehanika & dubina (po SKU-u)",
        bullets=[
            "Discount % — klasično 10%, 20%, 30% itd.",
            "1+1 — kupi 1 dobiješ 1 (efektivno 50%).",
            "2+1 — kupi 2 dobiješ 1 gratis (efektivno ~33%).",
            "3+1 — kupi 3 dobiješ 1 gratis (efektivno 25%).",
            "Tool sam izračuna efektivnu cijenu po komadu i discount %.",
        ],
        screenshot_label="Mehanika dropdown + efektivna cijena",
    )),
    ("walkthrough", dict(
        section="03 · Planner", title="⚖️ NC30 compliance check",
        bullets=[
            "Sustav uspoređuje predloženu promo cijenu s NC30 (najnižom cijenom u zadnjih 30 dana).",
            "Zeleno — OK (cijena iznad NC30).",
            "Crveno — UPOZORENJE (cijena ispod NC30, ne smije se izvesti).",
            "Podaci se učitavaju iz GATH NC30 izvoza koji se osvježava periodički.",
        ],
        screenshot_label="NC30 status panel — green/red badges po SKU",
    )),
    ("walkthrough", dict(
        section="03 · Planner", title="💰 P&L / margin impact",
        bullets=[
            "Po SKU-u: regularna cijena vs. promo cijena, jedinična marža, jedinični RUC.",
            "Procjena količine: analog forecast (sličan promo iz povijesti × pattern).",
            "Totals: ukupan prihod, ukupan RUC, % marže.",
            "Sve se računa live — promijeniš discount i brojevi se ažuriraju trenutno.",
        ],
        screenshot_label="P&L tablica s totals retkom",
    )),
    ("walkthrough", dict(
        section="03 · Planner", title="📜 Promo history za odabrani SKU",
        bullets=[
            "Lista svih prethodnih akcija s istim SKU-om iz ERP promo kalendara.",
            "Po retku: tjedni, mehanika, dubina, uplift faktor, prodane količine.",
            "🔍 Shadow promos — količinski spike bez ERP zapisa — flagga 'nešto se dogodilo'.",
            "Pomaže CM-u da ne ponavlja akciju koja ranije nije proradila.",
        ],
        screenshot_label="Tablica povijesnih akcija + shadow promos",
    )),
    ("walkthrough", dict(
        section="03 · Planner", title="📦 Coverage & stock",
        bullets=[
            "Trenutna količina na zalihi (centralni WH + dućani HR/AT/SLO).",
            "Forward coverage — koliko tjedana traje stock pri planiranoj prodaji.",
            "Otvoreni PO-ovi (incoming supply) u sljedećih 13 tjedana.",
            "Flag ako akcija ne bi imala dovoljno robe za pokriti predviđenu prodaju.",
        ],
        screenshot_label="Coverage table + incoming supply",
    )),
    ("walkthrough", dict(
        section="03 · Planner", title="✏️ Override per-week količina",
        bullets=[
            "Analog forecast daje tjedni pattern (ramp-peak-decline).",
            "CM može manualno editirati količinu po tjednu ako poznaje specifičnost.",
            "Override se zadržava i koristi u P&L kalkulaciji.",
        ],
        screenshot_label="Editable per-week qty grid",
    )),
    ("walkthrough", dict(
        section="03 · Planner", title="🔀 Cannibalization (sub-kategorija)",
        bullets=[
            "Sustav identificira 'sestrinske' SKU-ove iz iste sub-kategorije.",
            "Prikazuje očekivani gubitak prodaje na sestrama (cannibalization rate).",
            "Pomaže donijeti odluku — vrijedi li akcija ako kanibalizira ostatak portfelja.",
        ],
        screenshot_label="Cannibalization tablica",
    )),
    ("walkthrough", dict(
        section="03 · Planner", title="🚀 Save  ·  📤 Submit",
        bullets=[
            "🚀 Create & save — sprema akciju lokalno u cm_promotions.csv (za retro-analizu).",
            "📤 Submit to Promo Calendar — šalje prijedlog direktoru nabave s statusom 💡 idea.",
            "Submit prenosi i SKU listu i sve projekcije (units / prihod / RUC).",
        ],
        screenshot_label="Save + Submit gumbi",
    )),

    ("section", dict(
        label="04",
        title="Moji prijedlozi",
    )),
    ("walkthrough", dict(
        section="04 · Moji prijedlozi", title="Pregled svih akcija",
        bullets=[
            "4 KPI: Trebaju doradu · U pregledu · Odobreno · Live.",
            "5 tabova po statusu + 'Sve'.",
            "Po retku: status, source, period, broj SKU-ova, units.",
            "Zadnji audit log entry — npr. komentar direktora.",
        ],
        screenshot_label="Moji prijedlozi — tab Sve",
    )),
    ("walkthrough", dict(
        section="04 · Moji prijedlozi", title="Re-submit flow",
        bullets=[
            "Ako direktor vrati prijedlog → status 🔧 'Trebaju doradu'.",
            "CM vidi komentar direktora u kartici.",
            "Revidira prijedlog (kroz Planner ako treba ozbiljnu promjenu).",
            "🔁 Re-submit — status nazad na 💡 idea, direktor ga opet vidi.",
        ],
        screenshot_label="Tab Trebaju doradu s Re-submit gumbom",
    )),

    ("section", dict(
        label="05",
        title="Promo Forecaster",
    )),
    ("walkthrough", dict(
        section="05 · Forecaster", title="Preporuka discounta i trajanja",
        bullets=[
            "CM odabere SKU + cilj (Rješavanje lagera / Veći RUC / Traffic driver / Novi kupci).",
            "Tool predloži optimalan % discount i trajanje (npr. '20% kroz 2 tjedna').",
            "📈 Discount sensitivity — krivulja kako uplift raste s dubinom.",
            "📜 Backing — koji povijesni eventi su podloga preporuci.",
        ],
        screenshot_label="Forecaster — recommendation + sensitivity graf",
    )),

    ("section", dict(
        label="06",
        title="Past Promotions",
    )),
    ("walkthrough", dict(
        section="06 · History", title="Browser povijesnih akcija",
        bullets=[
            "Filtriraj po kategoriji, mehanici, izvoru, tjednu.",
            "📦 SKUs — lista artikala u svakoj kampanji.",
            "📊 Top 10 by uplift — najuspješnije akcije do sad.",
            "Koristi kad pripremaš novi prijedlog — uči iz onoga što je već radilo.",
        ],
        screenshot_label="Past Promotions browser",
    )),

    ("flow", dict()),

    ("section", dict(
        label="07",
        title="Sljedeći koraci",
    )),
    ("walkthrough", dict(
        section="07 · Next", title="Što slijedi",
        bullets=[
            "Pilot s jednim CM-om kroz cijeli ciklus (1–2 akcije od kraja do kraja).",
            "Marketing tim dobiva svoju Promo Tool verziju (web aktivacije).",
            "Promo Calendar dio za direktora nabave (odobravanje + konflikti).",
            "Dugoročno: deployment na IT Docker — bez .bat skripti, svatko ima link.",
            "Q&A — pitanja, zahtjevi za dodatne značajke?",
        ],
        screenshot_label="(opcionalno: roadmap timeline)",
    )),
]

# Two passes: count slides for footer page x/N
total = len(slide_specs)
for i, (kind, kw) in enumerate(slide_specs, start=1):
    if kind == "title":
        slide_title(prs, idx=i, total=total, **kw)
    elif kind == "section":
        slide_section(prs, idx=i, total=total, **kw)
    elif kind == "walkthrough":
        slide_walkthrough(prs, idx=i, total=total, **kw)
    elif kind == "flow":
        slide_flow(prs, idx=i, total=total)


# Safe save
def _safe_save(prs, path: Path) -> Path:
    try:
        prs.save(path)
        return path
    except PermissionError:
        j = 1
        while True:
            alt = path.with_name(f"{path.stem}_v{j}{path.suffix}")
            if not alt.exists():
                break
            j += 1
        prs.save(alt)
        return alt


OUT = Path(__file__).parent / "docs" / "Promo_Tool_Presentation.pptx"
OUT.parent.mkdir(parents=True, exist_ok=True)
written = _safe_save(prs, OUT)
print(f"Generated: {written}  ({written.stat().st_size // 1024} KB)")
print(f"Slides: {total}")
print()
print("Sljedeci korak:")
print("  1. Otvori .pptx u PowerPoint-u.")
print("  2. Pokreni Promo Tool (Start_PromoTool.bat) i napravi screenshote po stranicama.")
print("  3. Klikni svaki '[Screenshot here]' placeholder i Paste screenshot iznad njega.")
print("  4. Po potrebi prilagodi bullete prije sastanka.")
