#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""v1.2 visuele polish — training + master. Inhoud wordt NOOIT gewijzigd."""
import copy
from pptx import Presentation
from pptx.util import Emu, Pt
from pptx.dml.color import RGBColor
from pptx.enum.shapes import MSO_SHAPE
from pptx.enum.text import PP_ALIGN
from pptx.oxml.ns import qn

NAVY   = RGBColor(0x00, 0x33, 0x66)
NAVY2  = RGBColor(0x0A, 0x16, 0x28)
ORANGE = RGBColor(0xFF, 0x6D, 0x00)
CARD   = RGBColor(0xF8, 0xF9, 0xFA)
BORDER = RGBColor(0xE5, 0xE7, 0xEB)
GREEN  = RGBColor(0x00, 0xA8, 0x59)
WHITE  = RGBColor(0xFF, 0xFF, 0xFF)
LIGHT  = RGBColor(0xE5, 0xE7, 0xEB)

def add_shadow(shape):
    spPr = shape._element.spPr
    if spPr.find(qn('a:effectLst')) is not None:
        return
    eff = spPr.makeelement(qn('a:effectLst'), {})
    shdw = spPr.makeelement(qn('a:outerShdw'), {
        'blurRad': '63500', 'dist': '25400', 'dir': '5400000', 'rotWithShape': '0'})
    clr = spPr.makeelement(qn('a:srgbClr'), {'val': '000000'})
    alpha = spPr.makeelement(qn('a:alpha'), {'val': '20000'})
    clr.append(alpha); shdw.append(clr); eff.append(shdw); spPr.append(eff)

def set_alpha(shape, pct):
    """pct = opacity 0-100"""
    srgb = shape._element.spPr.find(qn('a:solidFill') + '/' + qn('a:srgbClr'))
    if srgb is None:
        for el in shape._element.spPr.iter(qn('a:srgbClr')):
            srgb = el; break
    if srgb is not None:
        a = srgb.makeelement(qn('a:alpha'), {'val': str(int(pct * 1000))})
        srgb.append(a)

def solid(shape, color, line_color=None, line_w=Pt(0.75)):
    shape.fill.solid()
    shape.fill.fore_color.rgb = color
    if line_color is None:
        shape.line.fill.background()
    else:
        shape.line.color.rgb = line_color
        shape.line.width = line_w

def card_style(shape):
    solid(shape, CARD, BORDER)
    add_shadow(shape)

def send_to_back(slide, shape):
    sp = shape._element
    sp.getparent().remove(sp)
    slide.shapes._spTree.insert(2, sp)

def gradient_fullbleed(shape):
    try:
        f = shape.fill
        f.gradient()
        stops = f.gradient_stops
        stops[0].color.rgb = NAVY
        stops[0].position = 0.0
        stops[1].color.rgb = NAVY2
        stops[1].position = 1.0
        while len(f.gradient_stops._gradFill.findall(qn('a:gsLst') + '/' + qn('a:gs'))) > 2:
            gs = f.gradient_stops._gradFill.find(qn('a:gsLst')).findall(qn('a:gs'))[-1]
            gs.getparent().remove(gs)
        f.gradient_angle = 115.0
    except Exception:
        solid(shape, NAVY)

def split_check_run(shape):
    """Split leading ✓ into its own run; kleur groen bold. Retourneert count."""
    n = 0
    for para in shape.text_frame.paragraphs:
        for run in list(para.runs):
            t = run.text
            if t.startswith('✓'):
                rest = t[1:].lstrip(' ')
                r_el = run._r
                new_r = copy.deepcopy(r_el)
                # nieuw run = ✓
                for tnode in new_r.findall(qn('a:t')):
                    tnode.text = '✓ '
                r_el.addprevious(new_r)
                run.text = rest if rest else run.text
                # style het ✓-run
                from pptx.text.text import _Run
                badge = _Run(new_r, para)
                badge.font.color.rgb = GREEN
                badge.font.bold = True
                n += 1
    return n

# ---------------------------------------------------------------- TRAINING
def polish_training(path):
    prs = Presentation(path)
    log = {'title': [], 'bars': [], 'bullets': 0, 'checks': [], 'slides': len(prs.slides)}

    # ---- Slide 1: titelfolie ----
    s1 = prs.slides[0]
    # full-bleed gradient achter alles
    bg = s1.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, prs.slide_width, prs.slide_height)
    gradient_fullbleed(bg)
    bg.line.fill.background()
    send_to_back(s1, bg)
    # oranje diagonaal accentvlak (~15% breed, transparant)
    diag = s1.shapes.add_shape(MSO_SHAPE.RECTANGLE,
                               Emu(-182880), Emu(-514350), Emu(1371600), Emu(6172200))
    solid(diag, ORANGE)
    set_alpha(diag, 22)
    diag.line.fill.background()
    diag.rotation = 20.0
    # titel: wit 40pt bold
    for sh in s1.shapes:
        if sh.has_text_frame and 'inhaleerbaar' in sh.text_frame.text.lower() and sh.top < 3000000 and sh.height > 1000000:
            for para in sh.text_frame.paragraphs:
                for run in para.runs:
                    run.font.size = Pt(40)
                    run.font.bold = True
                    run.font.color.rgb = WHITE
            log['title'].append(sh.shape_id)
        elif sh.has_text_frame and 'Master Training' in sh.text_frame.text:
            for para in sh.text_frame.paragraphs:
                for run in para.runs:
                    if run.font.color and run.font.color.type is not None:
                        try:
                            if run.font.color.rgb != WHITE:
                                run.font.color.rgb = LIGHT
                        except Exception:
                            run.font.color.rgb = LIGHT
                    else:
                        run.font.color.rgb = LIGHT

    # ---- Content slides ----
    for i, slide in enumerate(prs.slides, 1):
        if i == 1:
            continue
        # titelshape = tekstshape met kleinste top
        title = None
        for sh in slide.shapes:
            if sh.has_text_frame and sh.text_frame.text.strip():
                if title is None or sh.top < title.top:
                    title = sh
        if title is not None:
            bar = slide.shapes.add_shape(
                MSO_SHAPE.RECTANGLE, title.left,
                Emu(int(title.top + title.height) - 18288),
                Emu(1828800), Emu(36576))
            solid(bar, ORANGE)
            bar.line.fill.background()
            bar.shadow.inherit = False
            log['bars'].append(i)
        # bullets + checkmark-cards
        for sh in slide.shapes:
            if not sh.has_text_frame:
                continue
            txt = sh.text_frame.text.strip()
            if txt.startswith('•'):
                card_style(sh)
                log['bullets'] += 1
            elif txt.startswith('✓'):
                card_style(sh)
                n = split_check_run(sh)
                if n:
                    log['checks'].append((i, n))
    prs.save(path)
    return log

# ---------------------------------------------------------------- MASTER
def polish_master(path):
    prs = Presentation(path)
    log = {'bars_recolored': [], 'bullets': 0, 'slides': len(prs.slides)}
    for i, slide in enumerate(prs.slides, 1):
        for sh in slide.shapes:
            if not sh.has_text_frame:
                continue
            txt = sh.text_frame.text.strip()
            # accentbalken: bestaande dunne rectangles onder titelblok
            if txt.startswith('•'):
                card_style(sh)
                log['bullets'] += 1
        # recolour bestaande accentbalken (h≈0.04-0.05", w tussen 1" en 2")
        for sh in slide.shapes:
            if (sh.shape_type == MSO_SHAPE.RECTANGLE or str(sh.shape_type).startswith('AUTO')
                    or str(sh.shape_type).startswith('RECT')):
                pass
            try:
                h = int(sh.height); w = int(sh.width)
                if 35000 <= h <= 48000 and 1200000 <= w <= 1600000:
                    solid(sh, ORANGE)
                    sh.line.fill.background()
                    log['bars_recolored'].append(i)
            except Exception:
                pass
    prs.save(path)
    return log

if __name__ == '__main__':
    import json
    t = polish_training('deliverables/JvG_Training_Inhaleerbaar_Stof_v1.2.pptx')
    m = polish_master('deliverables/JvG_Training_Master_v1.2.pptx')
    print(json.dumps({'training': t, 'master': m}, indent=1, ensure_ascii=False))
