#!/usr/bin/env python3
"""PPTX Generator — JvG Consultancy Premium huisstijl training presentaties.
Generates consultancy-grade PowerPoint presentations from AI markdown output.
Golden Standard: Arcadis / Big4 niveau.
"""

import re
from datetime import datetime
from pptx import Presentation
from pptx.util import Inches, Pt, Emu, Cm
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE

PRIMARY = RGBColor(0x00, 0x33, 0x66)
ACCENT = RGBColor(0x4E, 0xCD, 0xC4)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
DARK = RGBColor(0x1F, 0x29, 0x37)
DARK_SECONDARY = RGBColor(0x37, 0x41, 0x51)
GREY = RGBColor(0xAD, 0xB5, 0xBD)
GREY_LIGHT = RGBColor(0x6C, 0x75, 0x7D)
LIGHT_BG = RGBColor(0xF0, 0xF4, 0xF8)
HEADER_HEIGHT = Cm(3)


def add_bg_rect(slide, color, left=0, top=0, width=None, height=None):
    prs_width = Emu(12192000)
    prs_height = Emu(6858000)
    w = width or prs_width
    h = height or prs_height
    shape = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, left, top, w, h)
    shape.fill.solid()
    shape.fill.fore_color.rgb = color
    shape.line.fill.background()
    return shape


def add_text_box(slide, text, left, top, width, height, font_size=18,
                 color=DARK, bold=False, alignment=PP_ALIGN.LEFT, font_name='Calibri',
                 italic=False):
    txBox = slide.shapes.add_textbox(left, top, width, height)
    tf = txBox.text_frame
    tf.word_wrap = True
    p = tf.paragraphs[0]
    p.text = text
    p.font.size = Pt(font_size)
    p.font.color.rgb = color
    p.font.bold = bold
    p.font.name = font_name
    p.font.italic = italic
    p.alignment = alignment
    return txBox


def add_slide_number(slide, num, total):
    """Add slide number at bottom right."""
    add_text_box(slide, f'{num} / {total}', Inches(11.8), Inches(7.0),
                 Inches(1.2), Inches(0.3), font_size=9, color=GREY,
                 alignment=PP_ALIGN.RIGHT)


def add_content_slide_chrome(slide, title_text, slide_num, total_slides):
    """Add standard content slide chrome: header bar, title, accent line, footer."""
    # White background
    add_bg_rect(slide, WHITE)
    # Header bar (3cm)
    add_bg_rect(slide, PRIMARY, Inches(0), Inches(0), prs_width := Emu(12192000), HEADER_HEIGHT)
    # Accent line under header
    add_bg_rect(slide, ACCENT, Inches(0), HEADER_HEIGHT, prs_width, Inches(0.05))
    # JvG Consultancy in header (left)
    add_text_box(slide, 'JvG Consultancy', Inches(0.5), Inches(0.15), Inches(4), Inches(0.5),
                 font_size=11, color=RGBColor(0xA0, 0xC4, 0xE8), bold=False, font_name='Calibri')
    # Title in header
    add_text_box(slide, title_text, Inches(0.8), Inches(0.7), Inches(11), Inches(0.8),
                 font_size=24, color=WHITE, bold=True, font_name='Calibri')
    # Footer
    add_text_box(slide, 'JvG Consultancy — HSEQ Intelligence', Inches(0.5), Inches(7.0),
                 Inches(8), Inches(0.3), font_size=8, color=GREY)
    # Slide number
    add_slide_number(slide, slide_num, total_slides)


def add_styled_table_to_slide(slide, headers, rows, left, top, width, height):
    """Add a premium styled table to a slide."""
    rows_count = len(rows) + 1
    cols_count = len(headers)
    table_shape = slide.shapes.add_table(rows_count, cols_count, left, top, width, height)
    table = table_shape.table

    # Set column widths evenly
    col_width = int(width / cols_count)
    for i in range(cols_count):
        table.columns[i].width = col_width

    # Header row
    for i, h in enumerate(headers):
        cell = table.cell(0, i)
        cell.text = ''
        p = cell.text_frame.paragraphs[0]
        run = p.add_run()
        run.text = h
        run.font.size = Pt(12)
        run.font.bold = True
        run.font.color.rgb = WHITE
        run.font.name = 'Calibri'
        # Dark blue background
        cell.fill.solid()
        cell.fill.fore_color.rgb = PRIMARY
        cell.vertical_anchor = MSO_ANCHOR.MIDDLE

    # Data rows
    for ri, row in enumerate(rows):
        for ci, val in enumerate(row):
            cell = table.cell(ri + 1, ci)
            cell.text = ''
            p = cell.text_frame.paragraphs[0]
            run = p.add_run()
            run.text = str(val)
            run.font.size = Pt(11)
            run.font.color.rgb = DARK_SECONDARY
            run.font.name = 'Calibri'
            cell.vertical_anchor = MSO_ANCHOR.MIDDLE
            # Alternating shading
            if ci == 0:
                cell.fill.solid()
                cell.fill.fore_color.rgb = LIGHT_BG
            elif ri % 2 == 1:
                cell.fill.solid()
                cell.fill.fore_color.rgb = RGBColor(0xF8, 0xFA, 0xFB)
            else:
                cell.fill.solid()
                cell.fill.fore_color.rgb = WHITE

    return table_shape


def parse_sections(text, max_bullets_per_slide=6, max_slides=18):
    """Parse AI text into slide sections, respecting max bullets."""
    sections = []
    current = {'title': '', 'bullets': [], 'level': 1, 'tables': []}

    for line in text.split('\n'):
        m = re.match(r'^(#{1,3})\s+(.+)', line)
        if m:
            if current['title'] or current['bullets'] or current['tables']:
                sections.append(current)
            current = {'title': m.group(2).strip(), 'bullets': [], 'level': len(m.group(1)), 'tables': []}
            continue

        stripped = line.strip()

        # Table detection
        if stripped.startswith('|') and '|' in stripped[1:]:
            cells = [c.strip() for c in stripped.split('|')[1:-1]]
            if not cells or all(set(c) <= {'-', '', ' '} for c in cells):
                continue
            if not current['tables']:
                current['tables'].append({'headers': [], 'rows': []})
            tbl = current['tables'][-1]
            if not tbl['headers']:
                tbl['headers'] = cells
            else:
                tbl['rows'].append(cells)
            continue

        bullet_text = stripped.lstrip('-•* ').strip()
        if bullet_text and len(bullet_text) > 3:
            bullet_text = re.sub(r'\*\*(.+?)\*\*', r'\1', bullet_text)
            current['bullets'].append(bullet_text)

    if current['title'] or current['bullets'] or current['tables']:
        sections.append(current)

    # Split sections with > max_bullets into multiple slides
    final = []
    for sec in sections:
        bullets = sec['bullets']
        tables = sec['tables']
        # If section has bullets + tables, put tables on separate slide
        if tables and bullets:
            final.append({'title': sec['title'], 'bullets': bullets[:max_bullets_per_slide], 'tables': []})
            for tbl in tables:
                final.append({'title': sec['title'], 'bullets': [], 'tables': [tbl]})
        elif bullets:
            while bullets:
                chunk = bullets[:max_bullets_per_slide]
                bullets = bullets[max_bullets_per_slide:]
                title = sec['title']
                if bullets:  # Add continuation marker
                    title = f'{sec["title"]} (vervolg)'
                final.append({'title': title, 'bullets': chunk, 'tables': []})
        elif tables:
            for tbl in tables:
                final.append({'title': sec['title'], 'bullets': [], 'tables': [tbl]})

    return final[:max_slides - 3]  # Reserve 3 for title, agenda, closing


def generate_pptx(title, category, intake, ai_text, sources=None):
    """Generate a premium branded PPTX training presentation."""
    prs = Presentation()
    prs.slide_width = Inches(13.333)
    prs.slide_height = Inches(7.5)

    sections = parse_sections(ai_text)
    total_slides = len(sections) + 3  # title + agenda + closing
    slide_counter = 0

    # ═══════════════════════════════════════════
    # SLIDE 1: TITLE SLIDE
    # ═══════════════════════════════════════════
    slide_counter += 1
    slide = prs.slides.add_slide(prs.slide_layouts[6])  # Blank
    add_bg_rect(slide, PRIMARY)

    # Accent line
    add_bg_rect(slide, ACCENT, Inches(0), Inches(3.5), prs.slide_width, Inches(0.06))

    # JvG Consultancy brand text (left bottom)
    add_text_box(slide, 'JvG Consultancy', Inches(0.8), Inches(6.2), Inches(4), Inches(0.5),
                 font_size=14, color=ACCENT, bold=False, alignment=PP_ALIGN.LEFT)

    # HSEQ Intelligence
    add_text_box(slide, 'HSEQ Intelligence', Inches(0.8), Inches(6.6), Inches(4), Inches(0.4),
                 font_size=11, color=RGBColor(0x80, 0xA0, 0xC0), alignment=PP_ALIGN.LEFT)

    # Main title
    add_text_box(slide, title, Inches(1), Inches(1.5), Inches(11.3), Inches(1.8),
                 font_size=40, color=WHITE, bold=True, alignment=PP_ALIGN.CENTER, font_name='Calibri')

    # Subtitle: category + date
    subtitle_parts = []
    if category:
        subtitle_parts.append(category)
    subtitle_parts.append(datetime.now().strftime('%d %B %Y'))
    add_text_box(slide, '  |  '.join(subtitle_parts), Inches(1), Inches(3.8), Inches(11.3), Inches(0.5),
                 font_size=16, color=ACCENT, alignment=PP_ALIGN.CENTER)

    # Versie
    add_text_box(slide, 'Versie 1.0', Inches(1), Inches(4.4), Inches(11.3), Inches(0.4),
                 font_size=12, color=RGBColor(0x80, 0xA0, 0xC0), alignment=PP_ALIGN.CENTER)

    notes = slide.notes_slide
    notes.notes_text_frame.text = f"Training: {title}\nDatum: {datetime.now().strftime('%d %B %Y')}\nPresentator: JvG Consultancy"

    # ═══════════════════════════════════════════
    # SLIDE 2: AGENDA
    # ═══════════════════════════════════════════
    slide_counter += 1
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    add_content_slide_chrome(slide, 'Agenda', slide_counter, total_slides)

    agenda_items = [s['title'] or 'Overig' for s in sections[:12]]
    y_start = 1.6
    for i, item in enumerate(agenda_items, 1):
        y = y_start + (i - 1) * 0.42
        # Number
        add_text_box(slide, f'{i:02d}', Inches(1.0), Inches(y), Inches(0.6), Inches(0.4),
                     font_size=14, color=ACCENT, bold=True, alignment=PP_ALIGN.RIGHT)
        # Dot separator
        add_text_box(slide, '·', Inches(1.7), Inches(y), Inches(0.3), Inches(0.4),
                     font_size=18, color=ACCENT)
        # Item text
        add_text_box(slide, item, Inches(2.0), Inches(y), Inches(10), Inches(0.4),
                     font_size=16, color=DARK_SECONDARY)

    notes = slide.notes_slide
    notes.notes_text_frame.text = "Agenda:\n" + "\n".join(f"{i}. {item}" for i, item in enumerate(agenda_items, 1))

    # ═══════════════════════════════════════════
    # CONTENT SLIDES
    # ═══════════════════════════════════════════
    for sec in sections:
        slide_counter += 1
        slide = prs.slides.add_slide(prs.slide_layouts[6])
        slide_title = sec['title'] or 'Inhoud'
        add_content_slide_chrome(slide, slide_title, slide_counter, total_slides)

        if sec['tables']:
            # Table slide
            for tbl in sec['tables']:
                if tbl.get('headers') and tbl.get('rows'):
                    display_rows = tbl['rows'][:8]  # Max 8 data rows
                    add_styled_table_to_slide(
                        slide, tbl['headers'], display_rows,
                        Inches(1.0), Inches(1.6), Inches(11.3), Inches(0.5 * (len(display_rows) + 1))
                    )
        elif sec['bullets']:
            # Bullet slide
            y = 1.8
            for bullet in sec['bullets']:
                # Bullet marker (teal diamond)
                add_text_box(slide, '◆', Inches(1.0), Inches(y - 0.02), Inches(0.4), Inches(0.4),
                             font_size=10, color=ACCENT)
                # Text
                add_text_box(slide, bullet, Inches(1.5), Inches(y), Inches(10.5), Inches(0.55),
                             font_size=16, color=DARK_SECONDARY)
                y += 0.6
                if y > 6.5:
                    break

        # Speaker notes
        if sec.get('bullets'):
            notes = slide.notes_slide
            notes.notes_text_frame.text = f"{slide_title}\n\n" + "\n".join(f"• {b}" for b in sec['bullets'])

    # ═══════════════════════════════════════════
    # CLOSING SLIDE
    # ═══════════════════════════════════════════
    slide_counter += 1
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    add_bg_rect(slide, PRIMARY)

    # Accent line
    add_bg_rect(slide, ACCENT, Inches(0), Inches(3.5), prs.slide_width, Inches(0.06))

    # "Vragen?"
    add_text_box(slide, 'Vragen?', Inches(1), Inches(2.0), Inches(11.3), Inches(1.2),
                 font_size=44, color=WHITE, bold=True, alignment=PP_ALIGN.CENTER, font_name='Calibri')

    # Subtitle
    add_text_box(slide, 'Bedankt voor uw aandacht', Inches(1), Inches(3.8), Inches(11.3), Inches(0.6),
                 font_size=20, color=RGBColor(0xA0, 0xC4, 0xE8), alignment=PP_ALIGN.CENTER)

    # Contact info
    add_text_box(slide, 'JvG Consultancy — HSEQ Intelligence', Inches(1), Inches(5.0), Inches(11.3), Inches(0.5),
                 font_size=16, color=ACCENT, alignment=PP_ALIGN.CENTER)

    add_text_box(slide, 'Neem contact op via het HSEQ Intelligence Dashboard', Inches(1), Inches(5.6), Inches(11.3), Inches(0.4),
                 font_size=13, color=RGBColor(0x80, 0xA0, 0xC0), alignment=PP_ALIGN.CENTER, italic=True)

    notes = slide.notes_slide
    notes.notes_text_frame.text = f"Afsluiting training: {title}\n\nVragen en discussie.\nJvG Consultancy — HSEQ Intelligence"

    return prs
