"""
Mod Comms — PowerPoint Presentation Generator
Generates a professional 16:9 widescreen presentation showcasing all features.
"""

import os
from pathlib import Path
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE

# ---------------------------------------------------------------------------
# Paths
# ---------------------------------------------------------------------------
SCRIPT_DIR = Path(__file__).resolve().parent
PROJECT_ROOT = SCRIPT_DIR.parent
LOGO_PATH = PROJECT_ROOT / "UI_guidance" / "Barclays-Modcomms.png"
OUTPUT_PPTX = SCRIPT_DIR / "ModComms_Presentation.pptx"

# ---------------------------------------------------------------------------
# Design tokens
# ---------------------------------------------------------------------------
DARK_NAVY = RGBColor(0x1A, 0x21, 0x42)
ACTIVE_BLUE = RGBColor(0x00, 0x6D, 0xE3)
ELECTRIC_VIOLET = RGBColor(0x7A, 0x0F, 0xF9)
LIME = RGBColor(0xC3, 0xFB, 0x5A)
TEAL = RGBColor(0x01, 0xA1, 0xA2)
CYAN_BRAND = RGBColor(0x00, 0xAE, 0xEF)

WHITE = RGBColor(0xFF, 0xFF, 0xFF)
BLACK_TITLE = RGBColor(0x27, 0x27, 0x27)
GREY_700 = RGBColor(0x8E, 0x8E, 0x8E)
GREY_300 = RGBColor(0xE2, 0xE2, 0xE2)
GREY_100 = RGBColor(0xF6, 0xF6, 0xF6)

RAG_GREEN = RGBColor(0x09, 0x82, 0x1F)
RAG_AMBER = RGBColor(0xFF, 0xBA, 0x00)
RAG_RED = RGBColor(0xE3, 0x00, 0x0F)

FONT_NAME = "Arial"

# Slide dimensions (16:9)
SLIDE_WIDTH = Inches(13.333)
SLIDE_HEIGHT = Inches(7.5)

# Margins
MARGIN_LEFT = Inches(0.8)
MARGIN_RIGHT = Inches(0.8)
MARGIN_TOP = Inches(0.6)
CONTENT_WIDTH = SLIDE_WIDTH - MARGIN_LEFT - MARGIN_RIGHT

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def set_slide_bg(slide, color):
    """Set a solid background colour for a slide."""
    bg = slide.background
    fill = bg.fill
    fill.solid()
    fill.fore_color.rgb = color


def add_textbox(slide, left, top, width, height, text, font_size=18,
                color=BLACK_TITLE, bold=False, alignment=PP_ALIGN.LEFT,
                font_name=FONT_NAME, line_spacing=1.2):
    """Add a simple single-run text box and return the shape."""
    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.alignment = alignment
    p.space_after = Pt(0)
    p.space_before = Pt(0)
    if line_spacing != 1.0:
        p.line_spacing = Pt(font_size * line_spacing)
    return txBox


def add_bullet_list(slide, left, top, width, height, items, font_size=14,
                    color=BLACK_TITLE, bullet_color=ACTIVE_BLUE, line_spacing=1.5):
    """Add a bulleted list text box. Each item is a separate paragraph."""
    txBox = slide.shapes.add_textbox(left, top, width, height)
    tf = txBox.text_frame
    tf.word_wrap = True

    for i, item in enumerate(items):
        if i == 0:
            p = tf.paragraphs[0]
        else:
            p = tf.add_paragraph()
        p.text = item
        p.font.size = Pt(font_size)
        p.font.color.rgb = color
        p.font.name = FONT_NAME
        p.space_after = Pt(4)
        p.space_before = Pt(2)
        p.line_spacing = Pt(font_size * line_spacing)
        # Bullet
        pPr = p._pPr
        if pPr is None:
            from pptx.oxml.ns import qn
            pPr = p._p.get_or_add_pPr()
        from pptx.oxml.ns import qn
        buNone = pPr.find(qn("a:buNone"))
        if buNone is not None:
            pPr.remove(buNone)
        buChar = pPr.makeelement(qn("a:buChar"), {"char": "\u2022"})
        pPr.append(buChar)
        buClr = pPr.makeelement(qn("a:buClr"), {})
        srgbClr = buClr.makeelement(qn("a:srgbClr"), {"val": f"{bullet_color}"})
        buClr.append(srgbClr)
        pPr.append(buClr)
        buSzPct = pPr.makeelement(qn("a:buSzPct"), {"val": "120000"})
        pPr.append(buSzPct)
        # Indent
        pPr.set("marL", str(Emu(Inches(0.3))))
        pPr.set("indent", str(Emu(Inches(-0.25))))

    return txBox


def add_rounded_rect(slide, left, top, width, height, fill_color, text="",
                     font_size=12, font_color=WHITE, bold=False, line_color=None):
    """Add a rounded rectangle shape with optional text."""
    shape = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, left, top, width, height)
    shape.fill.solid()
    shape.fill.fore_color.rgb = fill_color
    if line_color:
        shape.line.color.rgb = line_color
        shape.line.width = Pt(1.5)
    else:
        shape.line.fill.background()
    # Smaller corner radius
    shape.adjustments[0] = 0.1
    if text:
        tf = shape.text_frame
        tf.word_wrap = True
        tf.paragraphs[0].alignment = PP_ALIGN.CENTER
        p = tf.paragraphs[0]
        p.text = text
        p.font.size = Pt(font_size)
        p.font.color.rgb = font_color
        p.font.bold = bold
        p.font.name = FONT_NAME
        tf.margin_left = Pt(6)
        tf.margin_right = Pt(6)
        tf.margin_top = Pt(4)
        tf.margin_bottom = Pt(4)
    return shape


def add_circle(slide, left, top, diameter, fill_color, text="", font_size=11,
               font_color=WHITE, bold=True):
    """Add a circle shape with centered text."""
    shape = slide.shapes.add_shape(MSO_SHAPE.OVAL, left, top, diameter, diameter)
    shape.fill.solid()
    shape.fill.fore_color.rgb = fill_color
    shape.line.fill.background()
    if text:
        tf = shape.text_frame
        tf.word_wrap = True
        tf.paragraphs[0].alignment = PP_ALIGN.CENTER
        p = tf.paragraphs[0]
        p.text = text
        p.font.size = Pt(font_size)
        p.font.color.rgb = font_color
        p.font.bold = bold
        p.font.name = FONT_NAME
        tf.margin_left = Pt(2)
        tf.margin_right = Pt(2)
        tf.margin_top = Pt(2)
        tf.margin_bottom = Pt(2)
    return shape


def add_connector_line(slide, start_x, start_y, end_x, end_y, color=GREY_300, width=1.5):
    """Add a straight connector line."""
    connector = slide.shapes.add_connector(
        1,  # MSO_CONNECTOR.STRAIGHT
        start_x, start_y, end_x, end_y
    )
    connector.line.color.rgb = color
    connector.line.width = Pt(width)
    return connector


def add_rich_textbox(slide, left, top, width, height):
    """Add a text box and return the text frame for manual paragraph building."""
    txBox = slide.shapes.add_textbox(left, top, width, height)
    tf = txBox.text_frame
    tf.word_wrap = True
    return tf


# ---------------------------------------------------------------------------
# Slide builders
# ---------------------------------------------------------------------------

def make_title_slide(prs):
    """Slide 1: Title slide with logo."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])  # blank
    set_slide_bg(slide, DARK_NAVY)

    # Logo
    if LOGO_PATH.exists():
        slide.shapes.add_picture(
            str(LOGO_PATH),
            Inches(0.8), Inches(1.0),
            height=Inches(1.8)
        )

    # Title
    add_textbox(slide, Inches(0.8), Inches(3.2), Inches(10), Inches(1.0),
                "AI-Powered Proof Review", font_size=40, color=WHITE, bold=True)

    # Subtitle
    tf = add_rich_textbox(slide, Inches(0.8), Inches(4.2), Inches(10), Inches(0.8))
    p = tf.paragraphs[0]
    run1 = p.add_run()
    run1.text = "Automated compliance, brand, and channel analysis for "
    run1.font.size = Pt(20)
    run1.font.color.rgb = GREY_300
    run1.font.name = FONT_NAME
    run2 = p.add_run()
    run2.text = "Barclays"
    run2.font.size = Pt(20)
    run2.font.color.rgb = LIME
    run2.font.bold = True
    run2.font.name = FONT_NAME
    run3 = p.add_run()
    run3.text = " marketing materials"
    run3.font.size = Pt(20)
    run3.font.color.rgb = GREY_300
    run3.font.name = FONT_NAME

    # Built by line
    add_textbox(slide, Inches(0.8), Inches(5.4), Inches(6), Inches(0.5),
                "Built by OLIVER Agency", font_size=14, color=GREY_700)

    # Decorative accent bar
    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Inches(0.8), Inches(3.05),
                                  Inches(2.0), Pt(4))
    bar.fill.solid()
    bar.fill.fore_color.rgb = LIME
    bar.line.fill.background()


def make_section_divider(prs, section_number, title, subtitle=""):
    """Section divider slide — dark navy with large number."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, DARK_NAVY)

    # Large section number
    add_textbox(slide, Inches(0.8), Inches(1.0), Inches(3), Inches(2.5),
                f"{section_number:02d}", font_size=96, color=LIME, bold=True)

    # Accent bar
    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Inches(0.8), Inches(3.6),
                                  Inches(2.0), Pt(4))
    bar.fill.solid()
    bar.fill.fore_color.rgb = LIME
    bar.line.fill.background()

    # Title
    add_textbox(slide, Inches(0.8), Inches(3.9), Inches(10), Inches(1.2),
                title, font_size=36, color=WHITE, bold=True)

    if subtitle:
        add_textbox(slide, Inches(0.8), Inches(5.1), Inches(10), Inches(0.8),
                    subtitle, font_size=18, color=GREY_300)


def make_content_slide(prs, title, bullets, subtitle=""):
    """Standard content slide with heading and bullet list."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, WHITE)

    # Title
    add_textbox(slide, MARGIN_LEFT, Inches(0.4), CONTENT_WIDTH, Inches(0.7),
                title, font_size=28, color=DARK_NAVY, bold=True)

    # Accent underline
    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, MARGIN_LEFT, Inches(1.05),
                                  Inches(1.5), Pt(3))
    bar.fill.solid()
    bar.fill.fore_color.rgb = ACTIVE_BLUE
    bar.line.fill.background()

    y_start = Inches(1.3)
    if subtitle:
        add_textbox(slide, MARGIN_LEFT, y_start, CONTENT_WIDTH, Inches(0.5),
                    subtitle, font_size=15, color=GREY_700)
        y_start = Inches(1.8)

    add_bullet_list(slide, MARGIN_LEFT, y_start, CONTENT_WIDTH, Inches(5.5),
                    bullets, font_size=15, color=BLACK_TITLE)

    return slide


def make_two_column_slide(prs, title, left_title, left_items, right_title, right_items):
    """Two-column content slide."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, WHITE)

    # Title
    add_textbox(slide, MARGIN_LEFT, Inches(0.4), CONTENT_WIDTH, Inches(0.7),
                title, font_size=28, color=DARK_NAVY, bold=True)

    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, MARGIN_LEFT, Inches(1.05),
                                  Inches(1.5), Pt(3))
    bar.fill.solid()
    bar.fill.fore_color.rgb = ACTIVE_BLUE
    bar.line.fill.background()

    col_width = Inches(5.5)
    gap = Inches(0.8)

    # Left column
    add_textbox(slide, MARGIN_LEFT, Inches(1.4), col_width, Inches(0.4),
                left_title, font_size=18, color=TEAL, bold=True)
    add_bullet_list(slide, MARGIN_LEFT, Inches(1.85), col_width, Inches(5.0),
                    left_items, font_size=14)

    # Right column
    right_left = MARGIN_LEFT + col_width + gap
    add_textbox(slide, right_left, Inches(1.4), col_width, Inches(0.4),
                right_title, font_size=18, color=TEAL, bold=True)
    add_bullet_list(slide, right_left, Inches(1.85), col_width, Inches(5.0),
                    right_items, font_size=14)

    return slide


# ---------------------------------------------------------------------------
# Specific slides
# ---------------------------------------------------------------------------

def make_agenda_slide(prs):
    """Slide 2: Agenda."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, WHITE)

    add_textbox(slide, MARGIN_LEFT, Inches(0.4), CONTENT_WIDTH, Inches(0.7),
                "Agenda", font_size=28, color=DARK_NAVY, bold=True)

    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, MARGIN_LEFT, Inches(1.05),
                                  Inches(1.5), Pt(3))
    bar.fill.solid()
    bar.fill.fore_color.rgb = ACTIVE_BLUE
    bar.line.fill.background()

    agenda_items = [
        ("01", "The Challenge", "Why manual proof review doesn't scale"),
        ("02", "Introducing Mod Comms", "AI-powered proof review at a glance"),
        ("03", "Multi-Agent AI System", "Four specialist agents + Lead Agent"),
        ("04", "Campaign Management", "Organising and tracking marketing proofs"),
        ("05", "Real-Time Analysis", "Live WebSocket-powered review"),
        ("06", "Feedback & Reporting", "Structured results and PDF export"),
        ("07", "Knowledge Base & Admin", "Managing guidelines, analytics, and access"),
        ("08", "Technical Architecture", "How it all fits together"),
    ]

    y = Inches(1.4)
    for num, title, desc in agenda_items:
        # Number
        add_textbox(slide, MARGIN_LEFT, y, Inches(0.6), Inches(0.45),
                    num, font_size=20, color=ACTIVE_BLUE, bold=True)
        # Title
        add_textbox(slide, Inches(1.5), y, Inches(4), Inches(0.3),
                    title, font_size=16, color=DARK_NAVY, bold=True)
        # Description
        add_textbox(slide, Inches(5.6), y + Inches(0.02), Inches(6), Inches(0.3),
                    desc, font_size=14, color=GREY_700)
        # Divider line
        if num != "08":
            line = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE,
                                           MARGIN_LEFT, y + Inches(0.48),
                                           CONTENT_WIDTH, Pt(0.75))
            line.fill.solid()
            line.fill.fore_color.rgb = GREY_300
            line.line.fill.background()
        y += Inches(0.58)


def make_problem_slide(prs):
    """Slide 4: Problem statement."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, WHITE)

    add_textbox(slide, MARGIN_LEFT, Inches(0.4), CONTENT_WIDTH, Inches(0.7),
                "The Manual Review Bottleneck", font_size=28, color=DARK_NAVY, bold=True)

    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, MARGIN_LEFT, Inches(1.05),
                                  Inches(1.5), Pt(3))
    bar.fill.solid()
    bar.fill.fore_color.rgb = ACTIVE_BLUE
    bar.line.fill.background()

    # Problem cards — 2x2 grid
    cards = [
        ("Slow Turnaround", "Manual review of each proof takes hours.\nCampaign launches are delayed\nwaiting for feedback."),
        ("Inconsistent Quality", "Different reviewers apply guidelines\ndifferently. Critical compliance\nissues are sometimes missed."),
        ("Scaling Challenges", "Hundreds of proofs across Social,\nDisplay, Email, and Print channels\noverwhelm review teams."),
        ("Knowledge Silos", "Brand guidelines, legal requirements,\nand channel specs live in separate\ndocuments — hard to cross-reference."),
    ]

    card_w = Inches(5.5)
    card_h = Inches(2.3)
    x_positions = [MARGIN_LEFT, MARGIN_LEFT + card_w + Inches(0.6)]
    y_positions = [Inches(1.5), Inches(4.1)]

    for idx, (card_title, card_desc) in enumerate(cards):
        x = x_positions[idx % 2]
        y = y_positions[idx // 2]

        # Card background
        card = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, card_w, card_h)
        card.fill.solid()
        card.fill.fore_color.rgb = GREY_100
        card.line.color.rgb = GREY_300
        card.line.width = Pt(1)
        card.adjustments[0] = 0.05

        # Red accent bar at top of card
        accent = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, x + Inches(0.2),
                                         y + Inches(0.2), Inches(0.3), Pt(4))
        accent.fill.solid()
        accent.fill.fore_color.rgb = RAG_RED
        accent.line.fill.background()

        # Title
        add_textbox(slide, x + Inches(0.7), y + Inches(0.1), card_w - Inches(1), Inches(0.4),
                    card_title, font_size=16, color=DARK_NAVY, bold=True)

        # Description
        add_textbox(slide, x + Inches(0.3), y + Inches(0.6), card_w - Inches(0.6), Inches(1.5),
                    card_desc, font_size=13, color=GREY_700, line_spacing=1.4)


def make_solution_slide(prs):
    """Slide 6: Solution overview with value proposition cards."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, WHITE)

    add_textbox(slide, MARGIN_LEFT, Inches(0.4), CONTENT_WIDTH, Inches(0.7),
                "How Mod Comms Solves This", font_size=28, color=DARK_NAVY, bold=True)

    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, MARGIN_LEFT, Inches(1.05),
                                  Inches(1.5), Pt(3))
    bar.fill.solid()
    bar.fill.fore_color.rgb = ACTIVE_BLUE
    bar.line.fill.background()

    cards = [
        (ACTIVE_BLUE, "Instant Analysis",
         "Four AI agents review every\nproof in parallel — results in\nseconds, not days."),
        (ELECTRIC_VIOLET, "Consistent Standards",
         "Every proof is checked against\nthe same guidelines. No more\nhuman inconsistency."),
        (TEAL, "Full Coverage",
         "Legal, Brand, Channel Best\nPractices, and Tech Specs —\nall checked simultaneously."),
        (RAG_GREEN, "Actionable Feedback",
         "Clear RAG status with specific,\nconstructive recommendations\nfor every issue found."),
    ]

    card_w = Inches(2.7)
    card_h = Inches(4.0)
    total_w = card_w * 4 + Inches(0.4) * 3
    start_x = (SLIDE_WIDTH - total_w) / 2

    for idx, (color, title, desc) in enumerate(cards):
        x = start_x + idx * (card_w + Inches(0.4))
        y = Inches(1.8)

        # Card
        card = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, card_w, card_h)
        card.fill.solid()
        card.fill.fore_color.rgb = DARK_NAVY
        card.line.fill.background()
        card.adjustments[0] = 0.06

        # Top accent bar
        accent = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE,
                                         x + Inches(0.3), y + Inches(0.3),
                                         Inches(0.8), Pt(4))
        accent.fill.solid()
        accent.fill.fore_color.rgb = color
        accent.line.fill.background()

        # Title
        add_textbox(slide, x + Inches(0.3), y + Inches(0.6), card_w - Inches(0.6), Inches(0.5),
                    title, font_size=16, color=LIME, bold=True)

        # Description
        add_textbox(slide, x + Inches(0.3), y + Inches(1.2), card_w - Inches(0.6), Inches(2.5),
                    desc, font_size=13, color=GREY_300, line_spacing=1.5)


def make_agent_architecture_slide(prs):
    """Slide 8: Agent architecture diagram."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, WHITE)

    add_textbox(slide, MARGIN_LEFT, Inches(0.3), CONTENT_WIDTH, Inches(0.6),
                "Multi-Agent Architecture", font_size=28, color=DARK_NAVY, bold=True)

    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, MARGIN_LEFT, Inches(0.88),
                                  Inches(1.5), Pt(3))
    bar.fill.solid()
    bar.fill.fore_color.rgb = ACTIVE_BLUE
    bar.line.fill.background()

    # --- Proof Upload box ---
    upload_x = Inches(0.5)
    upload_y = Inches(2.8)
    upload_w = Inches(1.8)
    upload_h = Inches(1.2)
    add_rounded_rect(slide, upload_x, upload_y, upload_w, upload_h,
                     GREY_100, "Proof\nUpload", font_size=14, font_color=DARK_NAVY,
                     bold=True, line_color=GREY_300)

    # --- Arrow from upload to agents area ---
    add_connector_line(slide, upload_x + upload_w, upload_y + upload_h / 2,
                       Inches(2.8), upload_y + upload_h / 2, ACTIVE_BLUE, 2)

    # --- Four specialist agents ---
    agent_x = Inches(2.8)
    agents = [
        (ACTIVE_BLUE, "Legal\nAgent"),
        (ELECTRIC_VIOLET, "Brand\nAgent"),
        (TEAL, "Channel Best\nPractices Agent"),
        (CYAN_BRAND, "Channel Tech\nSpecs Agent"),
    ]
    agent_w = Inches(2.0)
    agent_h = Inches(0.9)
    agent_gap = Inches(0.2)
    agents_total_h = len(agents) * agent_h + (len(agents) - 1) * agent_gap
    agent_start_y = Inches(1.2)

    for idx, (color, name) in enumerate(agents):
        y = agent_start_y + idx * (agent_h + agent_gap)
        add_rounded_rect(slide, agent_x, y, agent_w, agent_h,
                         color, name, font_size=12, font_color=WHITE, bold=True)
        # Arrow to lead agent
        add_connector_line(slide, agent_x + agent_w, y + agent_h / 2,
                           Inches(5.6), y + agent_h / 2, GREY_300, 1.5)

    # --- Gemini API box (below agents) ---
    gemini_x = Inches(2.8)
    gemini_y = agent_start_y + agents_total_h + Inches(0.4)
    add_rounded_rect(slide, gemini_x, gemini_y, agent_w, Inches(0.7),
                     DARK_NAVY, "Google Gemini 2.5 Flash",
                     font_size=11, font_color=LIME, bold=True)

    # Connector from Gemini to agents (vertical line on the left side)
    gem_center_x = gemini_x + agent_w / 2
    add_connector_line(slide, gem_center_x, agent_start_y + agents_total_h,
                       gem_center_x, gemini_y, GREY_300, 1.5)

    # --- Lead Agent (central) ---
    lead_x = Inches(5.6)
    lead_y = Inches(2.4)
    lead_w = Inches(2.2)
    lead_h = Inches(1.8)
    lead = add_rounded_rect(slide, lead_x, lead_y, lead_w, lead_h,
                            DARK_NAVY, "", line_color=LIME)

    # Lead agent text
    add_textbox(slide, lead_x + Inches(0.15), lead_y + Inches(0.2),
                lead_w - Inches(0.3), Inches(0.4),
                "Lead Agent", font_size=16, color=LIME, bold=True,
                alignment=PP_ALIGN.CENTER)
    add_textbox(slide, lead_x + Inches(0.15), lead_y + Inches(0.65),
                lead_w - Inches(0.3), Inches(0.9),
                "Synthesises all\nreviews into final\nstatus & summary",
                font_size=11, color=WHITE, alignment=PP_ALIGN.CENTER)

    # --- Arrow from lead to output ---
    add_connector_line(slide, lead_x + lead_w, lead_y + lead_h / 2,
                       Inches(8.5), lead_y + lead_h / 2, ACTIVE_BLUE, 2)

    # --- Knowledge Base box (below lead) ---
    kb_x = Inches(5.6)
    kb_y = gemini_y
    add_rounded_rect(slide, kb_x, kb_y, lead_w, Inches(0.7),
                     DARK_NAVY, "Knowledge Base",
                     font_size=11, font_color=LIME, bold=True)
    add_connector_line(slide, kb_x + lead_w / 2, lead_y + lead_h,
                       kb_x + lead_w / 2, kb_y, GREY_300, 1.5)

    # --- Output: RAG Status ---
    output_x = Inches(8.5)
    output_y = Inches(1.5)
    output_w = Inches(4.2)
    output_h = Inches(4.8)

    # Output container
    out_card = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE,
                                       output_x, output_y, output_w, output_h)
    out_card.fill.solid()
    out_card.fill.fore_color.rgb = GREY_100
    out_card.line.color.rgb = GREY_300
    out_card.line.width = Pt(1)
    out_card.adjustments[0] = 0.04

    add_textbox(slide, output_x + Inches(0.2), output_y + Inches(0.15),
                output_w - Inches(0.4), Inches(0.35),
                "Analysis Output", font_size=14, color=DARK_NAVY, bold=True,
                alignment=PP_ALIGN.CENTER)

    # RAG circles
    rag_items = [
        (RAG_GREEN, "Green", "Passed — compliant"),
        (RAG_AMBER, "Amber", "Minor issues to address"),
        (RAG_RED, "Red", "Failed — must resolve"),
    ]
    circle_d = Inches(0.4)
    rag_y = output_y + Inches(0.7)
    for idx, (color, label, desc) in enumerate(rag_items):
        cy = rag_y + idx * Inches(0.6)
        add_circle(slide, output_x + Inches(0.3), cy, circle_d, color,
                   "", font_size=9, bold=True)
        add_textbox(slide, output_x + Inches(0.85), cy + Inches(0.02),
                    Inches(1), Inches(0.35),
                    label, font_size=12, color=DARK_NAVY, bold=True)
        add_textbox(slide, output_x + Inches(1.8), cy + Inches(0.02),
                    Inches(2.2), Inches(0.35),
                    desc, font_size=11, color=GREY_700)

    # Overall status labels
    status_y = rag_y + Inches(2.0)
    statuses = [
        (RAG_GREEN, "Passed"),
        (RAG_AMBER, "Requires Manual Legal Review"),
        (RAG_RED, "Failed"),
        (GREY_700, "Analysis Error"),
    ]
    add_textbox(slide, output_x + Inches(0.2), status_y - Inches(0.3),
                output_w - Inches(0.4), Inches(0.3),
                "Overall Status:", font_size=12, color=DARK_NAVY, bold=True)
    for idx, (color, label) in enumerate(statuses):
        sy = status_y + idx * Inches(0.35)
        dot = slide.shapes.add_shape(MSO_SHAPE.OVAL,
                                      output_x + Inches(0.3), sy + Inches(0.05),
                                      Inches(0.15), Inches(0.15))
        dot.fill.solid()
        dot.fill.fore_color.rgb = color
        dot.line.fill.background()
        add_textbox(slide, output_x + Inches(0.6), sy,
                    Inches(3.2), Inches(0.3),
                    label, font_size=11, color=DARK_NAVY)


def make_legal_agent_slide(prs):
    """Slide 9: Legal Agent deep dive."""
    make_content_slide(prs, "Legal Agent",
        [
            "Detects financial promotions — interest rates, APR, credit products, savings rates",
            "Checks advertising standards compliance against ASA/CAP code",
            "Verifies required disclaimers are present, legible, and properly placed",
            "Assesses FCA regulatory compliance for financial services marketing",
            "Reviews terms and conditions — referenced where necessary, qualifying text clear",
            "Checks third-party content — permissions, attributions, influencer disclosures",
            "Financial promotion detected → overall status becomes 'Requires Manual Legal Review'",
            "Uses British English and constructive language throughout all feedback",
        ],
        subtitle="Compliance specialist ensuring all marketing materials meet legal and regulatory requirements")


def make_brand_agent_slide(prs):
    """Slide 10: Brand Agent deep dive."""
    make_two_column_slide(prs,
        "Brand Agent",
        "Barclays Brand Checks",
        [
            "Logo usage — correct version, minimum size, clear space, placement",
            "Colour palette — approved masterbrand colours, WCAG-compliant pairings",
            "Typography — Barclays Effra (Arial fallback), correct weights and scale",
            "Design principles — overall design reflects brand expression",
            "Sacred assets — present and unaltered",
            "Accessibility — legible font sizes, proper contrast ratios",
        ],
        "Barclaycard Specifics",
        [
            "Card Portal — stroke weight, corner radius, border colour, rotation limits",
            "Barclaycard-specific core principles and guidelines",
            "Experiential and email-specific guidelines applied",
            "Social media guidelines for Barclaycard-branded content",
            "Brand selection is per-campaign — agents load the correct spec dynamically",
            "15+ brand guideline documents in the Knowledge Base",
        ])


def make_channel_agents_slide(prs):
    """Slide 11: Channel agents deep dive."""
    make_two_column_slide(prs,
        "Channel Agents",
        "Best Practices Agent",
        [
            "Content strategy — messaging clarity, CTA effectiveness",
            "Creative best practices — visual hierarchy, engagement patterns",
            "Platform optimisation — algorithm tips, safe zones, text-to-image ratios",
            "Engagement — hashtags, mentions, tone suitability",
            "Mobile-first design — legibility, touch targets, thumb-zone navigation",
        ],
        "Tech Specs Agent",
        [
            "Dimensions & resolution — platform-specific sizes, DPI/PPI, aspect ratios",
            "File format — type, size limits, compression quality",
            "Typography specs — minimum font sizes, character counts",
            "Digital grid system — 12-col desktop, 6-col mobile, 8px baseline",
            "WCAG accessibility — colour contrast, documented pairings",
            "Platform-specific specs — safe zones, video formats, frame rates",
        ])


def make_rag_status_slide(prs):
    """Slide 12: RAG Status & Decision Logic."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, WHITE)

    add_textbox(slide, MARGIN_LEFT, Inches(0.4), CONTENT_WIDTH, Inches(0.7),
                "RAG Status & Decision Logic", font_size=28, color=DARK_NAVY, bold=True)

    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, MARGIN_LEFT, Inches(1.05),
                                  Inches(1.5), Pt(3))
    bar.fill.solid()
    bar.fill.fore_color.rgb = ACTIVE_BLUE
    bar.line.fill.background()

    # Agent RAG section
    add_textbox(slide, MARGIN_LEFT, Inches(1.3), Inches(5), Inches(0.4),
                "Per-Agent RAG Status", font_size=18, color=TEAL, bold=True)

    rag_items = [
        (RAG_GREEN, "Green", "Fully compliant — no issues found"),
        (RAG_AMBER, "Amber", "Minor issues that should be addressed"),
        (RAG_RED, "Red", "Significant issues that must be resolved"),
        (GREY_700, "Error", "Agent could not analyse with confidence"),
    ]

    for idx, (color, label, desc) in enumerate(rag_items):
        y = Inches(1.85) + idx * Inches(0.55)
        add_circle(slide, MARGIN_LEFT + Inches(0.2), y, Inches(0.35), color)
        add_textbox(slide, MARGIN_LEFT + Inches(0.75), y + Inches(0.02),
                    Inches(1), Inches(0.3), label, font_size=14, color=DARK_NAVY, bold=True)
        add_textbox(slide, MARGIN_LEFT + Inches(1.8), y + Inches(0.02),
                    Inches(4), Inches(0.3), desc, font_size=13, color=GREY_700)

    # Decision logic section
    add_textbox(slide, Inches(7.0), Inches(1.3), Inches(5.5), Inches(0.4),
                "Lead Agent Decision Logic", font_size=18, color=TEAL, bold=True)

    # Decision flow as cards
    decisions = [
        ("1", RAG_AMBER, "Financial promotion detected?",
         "→ Requires Manual Legal Review"),
        ("2", RAG_RED, "Any agent returned Error?",
         "→ Analysis Error"),
        ("3", RAG_RED, "Any agent returned Red?",
         "→ Failed"),
        ("4", RAG_GREEN, "Otherwise",
         "→ Passed"),
    ]

    for idx, (num, color, question, result) in enumerate(decisions):
        y = Inches(1.85) + idx * Inches(1.15)
        x = Inches(7.0)

        # Decision card
        card = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE,
                                       x, y, Inches(5.5), Inches(0.95))
        card.fill.solid()
        card.fill.fore_color.rgb = GREY_100
        card.line.color.rgb = GREY_300
        card.line.width = Pt(1)
        card.adjustments[0] = 0.08

        # Step number
        add_circle(slide, x + Inches(0.15), y + Inches(0.2), Inches(0.45),
                   color, num, font_size=14, font_color=WHITE)

        add_textbox(slide, x + Inches(0.75), y + Inches(0.1),
                    Inches(4.5), Inches(0.35),
                    question, font_size=13, color=DARK_NAVY, bold=True)
        add_textbox(slide, x + Inches(0.75), y + Inches(0.5),
                    Inches(4.5), Inches(0.35),
                    result, font_size=13, color=ACTIVE_BLUE, bold=True)


def make_campaign_lifecycle_slide(prs):
    """Slide 14: Campaign & proof lifecycle."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, WHITE)

    add_textbox(slide, MARGIN_LEFT, Inches(0.4), CONTENT_WIDTH, Inches(0.7),
                "Campaign & Proof Lifecycle", font_size=28, color=DARK_NAVY, bold=True)

    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, MARGIN_LEFT, Inches(1.05),
                                  Inches(1.5), Pt(3))
    bar.fill.solid()
    bar.fill.fore_color.rgb = ACTIVE_BLUE
    bar.line.fill.background()

    # Flow steps
    steps = [
        ("Create\nCampaign", "Set brand, agency,\nclient lead"),
        ("Upload\nProof", "Name, channel,\nsub-channel, type"),
        ("AI\nAnalysis", "4 agents analyse\nin parallel"),
        ("Review\nFeedback", "RAG status per\nagent + summary"),
        ("Resolve or\nRevise", "Mark issues resolved\nor upload new version"),
        ("Export\nReport", "PDF with full\nfeedback details"),
    ]

    step_w = Inches(1.7)
    step_h = Inches(1.3)
    desc_h = Inches(0.9)
    gap = Inches(0.25)
    total_w = len(steps) * step_w + (len(steps) - 1) * gap
    start_x = (SLIDE_WIDTH - total_w) / 2
    step_y = Inches(1.8)

    colors = [ACTIVE_BLUE, ELECTRIC_VIOLET, TEAL, ACTIVE_BLUE, ELECTRIC_VIOLET, TEAL]

    for idx, (title, desc) in enumerate(steps):
        x = start_x + idx * (step_w + gap)

        # Step box
        add_rounded_rect(slide, x, step_y, step_w, step_h,
                         colors[idx], title, font_size=13, font_color=WHITE, bold=True)

        # Description below
        add_textbox(slide, x, step_y + step_h + Inches(0.15), step_w, desc_h,
                    desc, font_size=11, color=GREY_700, alignment=PP_ALIGN.CENTER,
                    line_spacing=1.4)

        # Arrow
        if idx < len(steps) - 1:
            arrow_x = x + step_w
            arrow_y = step_y + step_h / 2
            add_connector_line(slide, arrow_x, arrow_y,
                               arrow_x + gap, arrow_y, GREY_300, 2)

    # Bottom section: Campaign table details
    add_textbox(slide, MARGIN_LEFT, Inches(4.4), CONTENT_WIDTH, Inches(0.4),
                "Campaign Table Features", font_size=16, color=TEAL, bold=True)

    add_bullet_list(slide, MARGIN_LEFT, Inches(4.9), Inches(5.5), Inches(2.5),
        [
            "Sortable, filterable columns — name, status, proof count, agency",
            "\"My Campaigns Only\" toggle for personal workspace",
            "Show/Hide Completed toggle",
            "Quick-create modal with brand guideline selection",
        ], font_size=13)

    add_textbox(slide, Inches(7.0), Inches(4.4), Inches(5.5), Inches(0.4),
                "Proof Management", font_size=16, color=TEAL, bold=True)

    add_bullet_list(slide, Inches(7.0), Inches(4.9), Inches(5.5), Inches(2.5),
        [
            "Dependent dropdowns: Channel → Sub-Channel → Proof Type",
            "Version history with download and comparison",
            "Duplicate file detection via MD5 hash",
            "Supported: Social, Display, Copy channels (22+ formats)",
        ], font_size=13)


def make_websocket_slide(prs):
    """Slide 16: WebSocket live analysis."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, WHITE)

    add_textbox(slide, MARGIN_LEFT, Inches(0.4), CONTENT_WIDTH, Inches(0.7),
                "Real-Time WebSocket Analysis", font_size=28, color=DARK_NAVY, bold=True)

    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, MARGIN_LEFT, Inches(1.05),
                                  Inches(1.5), Pt(3))
    bar.fill.solid()
    bar.fill.fore_color.rgb = ACTIVE_BLUE
    bar.line.fill.background()

    # Message flow diagram
    messages = [
        ("Client", ACTIVE_BLUE, "analyze", "File (base64) + metadata sent via WebSocket"),
        ("Server", TEAL, "agent_started", "\"Legal Agent is analysing...\""),
        ("Server", TEAL, "agent_completed", "Legal Agent review returned (RAG + feedback)"),
        ("Server", TEAL, "agent_started", "\"Brand Agent is analysing...\""),
        ("Server", TEAL, "agent_completed", "Brand Agent review returned"),
        ("Server", ELECTRIC_VIOLET, "summary", "Lead Agent summary generated"),
        ("Server", RAG_GREEN, "complete", "Full AgentReview + proof ID + version ID"),
    ]

    y = Inches(1.5)
    for sender, color, msg_type, desc in messages:
        # Direction indicator
        if sender == "Client":
            arrow_text = "→"
            label_color = ACTIVE_BLUE
        else:
            arrow_text = "←"
            label_color = TEAL

        # Message type badge
        add_rounded_rect(slide, MARGIN_LEFT, y, Inches(0.8), Inches(0.4),
                         GREY_100, sender, font_size=10, font_color=GREY_700,
                         line_color=GREY_300)

        add_textbox(slide, Inches(1.75), y + Inches(0.03), Inches(0.3), Inches(0.35),
                    arrow_text, font_size=16, color=label_color, bold=True)

        add_rounded_rect(slide, Inches(2.2), y, Inches(2.0), Inches(0.4),
                         color, msg_type, font_size=11, font_color=WHITE, bold=True)

        add_textbox(slide, Inches(4.4), y + Inches(0.05), Inches(5), Inches(0.35),
                    desc, font_size=12, color=GREY_700)

        y += Inches(0.55)

    # Right side: Key features
    add_textbox(slide, Inches(9.8), Inches(1.3), Inches(3), Inches(0.4),
                "Key Capabilities", font_size=16, color=TEAL, bold=True)

    add_bullet_list(slide, Inches(9.8), Inches(1.8), Inches(3.2), Inches(4.5),
        [
            "Parallel agent execution via asyncio.gather()",
            "Real-time progress — agents report as they finish",
            "PDF rasterisation (up to 10 pages)",
            "Revision-aware analysis with previous review context",
            "Authenticated via MSAL bearer token",
            "Automatic proof persistence to database",
        ], font_size=12)


def make_feedback_reports_slide(prs):
    """Slide 18: Feedback reports & PDF export."""
    make_two_column_slide(prs,
        "Feedback Reports & PDF Export",
        "Asset Detail View",
        [
            "Two-column layout: proof preview (left) + agent feedback (right)",
            "RAG status badge per agent with colour-coded indicators",
            "Detailed text feedback with constructive recommendations",
            "Actionable issues listed with 'Mark as Resolved' capability",
            "Resolution notes recorded for audit trail",
            "Flag incorrect feedback — sent to Auditing dashboard",
            "Version history with one-click navigation between versions",
        ],
        "PDF Export",
        [
            "Single Proof Report — detailed feedback for one proof",
            "Campaign Report — consolidated report for all proofs",
            "Cover page with Barclays branding, campaign name, date",
            "Proof preview with metadata (name, version, channel)",
            "Lead Agent summary with overall status",
            "Per-agent sections: RAG status, full feedback, issues list",
            "Professional formatting ready for stakeholder review",
        ])


def make_knowledge_base_slide(prs):
    """Slide 20: Knowledge Base management."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, WHITE)

    add_textbox(slide, MARGIN_LEFT, Inches(0.4), CONTENT_WIDTH, Inches(0.7),
                "Knowledge Base Management", font_size=28, color=DARK_NAVY, bold=True)

    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, MARGIN_LEFT, Inches(1.05),
                                  Inches(1.5), Pt(3))
    bar.fill.solid()
    bar.fill.fore_color.rgb = ACTIVE_BLUE
    bar.line.fill.background()

    # Pipeline steps
    pipe_steps = [
        ("Upload\nDocuments", "PDF or Markdown\nbrand/legal/channel\nguidelines"),
        ("Parse &\nConvert", "AI converts uploads\nto structured\nmarkdown"),
        ("Generate\nSpec", "AI synthesises all\ndocuments into\nunified specification"),
        ("Version\nControl", "New spec version\ncreated with diff\ncomparison"),
        ("Activate", "Admin selects\nwhich version\nagents use"),
    ]

    step_w = Inches(2.0)
    step_h = Inches(1.2)
    gap = Inches(0.35)
    total_w = len(pipe_steps) * step_w + (len(pipe_steps) - 1) * gap
    start_x = (SLIDE_WIDTH - total_w) / 2
    step_y = Inches(1.5)

    pipe_colors = [ACTIVE_BLUE, ELECTRIC_VIOLET, TEAL, ACTIVE_BLUE, RAG_GREEN]

    for idx, (title, desc) in enumerate(pipe_steps):
        x = start_x + idx * (step_w + gap)
        add_rounded_rect(slide, x, step_y, step_w, step_h,
                         pipe_colors[idx], title, font_size=13, font_color=WHITE, bold=True)
        add_textbox(slide, x, step_y + step_h + Inches(0.1), step_w, Inches(0.9),
                    desc, font_size=11, color=GREY_700, alignment=PP_ALIGN.CENTER,
                    line_spacing=1.4)
        if idx < len(pipe_steps) - 1:
            ax = x + step_w
            ay = step_y + step_h / 2
            add_connector_line(slide, ax, ay, ax + gap, ay, GREY_300, 2)

    # Knowledge bases list
    add_textbox(slide, MARGIN_LEFT, Inches(4.3), CONTENT_WIDTH, Inches(0.4),
                "Five Knowledge Bases", font_size=16, color=TEAL, bold=True)

    kbs = [
        ("Legal", "FCA regulations, ASA/CAP code, financial promotion rules"),
        ("Brand — Barclays", "15+ guideline documents covering logo, colour, typography, design"),
        ("Brand — Barclaycard", "Core principles, digital guidelines, email and social specs"),
        ("Channel Best Practices", "LinkedIn, Reddit, platform optimisation, creative inspiration"),
        ("Channel Tech Specs", "Social templates, dimension specs, platform-specific requirements"),
    ]

    kb_w = Inches(2.2)
    kb_h = Inches(1.8)
    kb_gap = Inches(0.25)
    total_kb_w = len(kbs) * kb_w + (len(kbs) - 1) * kb_gap
    kb_start_x = (SLIDE_WIDTH - total_kb_w) / 2
    kb_y = Inches(4.8)

    kb_colors = [ACTIVE_BLUE, ELECTRIC_VIOLET, ELECTRIC_VIOLET, TEAL, CYAN_BRAND]

    for idx, (name, desc) in enumerate(kbs):
        x = kb_start_x + idx * (kb_w + kb_gap)
        card = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE,
                                       x, kb_y, kb_w, kb_h)
        card.fill.solid()
        card.fill.fore_color.rgb = DARK_NAVY
        card.line.fill.background()
        card.adjustments[0] = 0.06

        # Accent
        accent = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE,
                                         x + Inches(0.2), kb_y + Inches(0.15),
                                         Inches(0.6), Pt(3))
        accent.fill.solid()
        accent.fill.fore_color.rgb = kb_colors[idx]
        accent.line.fill.background()

        add_textbox(slide, x + Inches(0.15), kb_y + Inches(0.35),
                    kb_w - Inches(0.3), Inches(0.35),
                    name, font_size=12, color=LIME, bold=True,
                    alignment=PP_ALIGN.CENTER)
        add_textbox(slide, x + Inches(0.15), kb_y + Inches(0.75),
                    kb_w - Inches(0.3), Inches(0.9),
                    desc, font_size=10, color=GREY_300,
                    alignment=PP_ALIGN.CENTER, line_spacing=1.4)


def make_admin_three_col_slide(prs):
    """Slide 21: Analytics, Auditing & Settings (3-column)."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, WHITE)

    add_textbox(slide, MARGIN_LEFT, Inches(0.4), CONTENT_WIDTH, Inches(0.7),
                "Analytics, Auditing & Settings", font_size=28, color=DARK_NAVY, bold=True)

    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, MARGIN_LEFT, Inches(1.05),
                                  Inches(1.5), Pt(3))
    bar.fill.solid()
    bar.fill.fore_color.rgb = ACTIVE_BLUE
    bar.line.fill.background()

    columns = [
        ("Analytics", ACTIVE_BLUE, [
            "Proofs Uploaded — total count",
            "Pass Rate — % of proofs that passed",
            "Issues Found — total across agents",
            "Time Saved — hours estimated",
            "AI Performance Summary — weekly trends",
            "Agent Performance Table — per-agent stats",
        ]),
        ("Auditing", ELECTRIC_VIOLET, [
            "Flags Tab — user-reported incorrect feedback",
            "Resolutions Tab — user-resolved issues",
            "Errors Tab — analysis failures",
            "Links to specific proof and version",
            "Full audit trail with timestamps",
            "Agency-filterable for oversight admins",
        ]),
        ("Settings", TEAL, [
            "Manage Channels — add/remove options",
            "Sub-Channels — dependent on parent",
            "Proof Types — dependent on sub-channel",
            "Changes propagate immediately",
            "Admin-only access for editing",
            "Oversight admins get read-only view",
        ]),
    ]

    col_w = Inches(3.7)
    col_gap = Inches(0.3)
    total_col_w = len(columns) * col_w + (len(columns) - 1) * col_gap
    start_x = (SLIDE_WIDTH - total_col_w) / 2

    for idx, (title, color, items) in enumerate(columns):
        x = start_x + idx * (col_w + col_gap)
        y = Inches(1.4)

        # Column header card
        add_rounded_rect(slide, x, y, col_w, Inches(0.5),
                         color, title, font_size=15, font_color=WHITE, bold=True)

        # Bullet list
        add_bullet_list(slide, x + Inches(0.1), y + Inches(0.7),
                        col_w - Inches(0.2), Inches(5.0),
                        items, font_size=13, line_spacing=1.4)


def make_user_roles_slide(prs):
    """Slide 22: User Roles & Access Control (table-style)."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, WHITE)

    add_textbox(slide, MARGIN_LEFT, Inches(0.4), CONTENT_WIDTH, Inches(0.7),
                "User Roles & Access Control", font_size=28, color=DARK_NAVY, bold=True)

    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, MARGIN_LEFT, Inches(1.05),
                                  Inches(1.5), Pt(3))
    bar.fill.solid()
    bar.fill.fore_color.rgb = ACTIVE_BLUE
    bar.line.fill.background()

    # Table data
    headers = ["Role", "Write", "Analytics", "Auditing", "Knowledge\nBase", "Settings", "User\nMgmt", "Agency\nFilter"]
    rows_data = [
        ["Super Admin", "\u2713", "\u2713", "\u2713", "\u2713", "Full", "\u2713", "\u2713"],
        ["Oversight Admin", "\u2717", "\u2713", "\u2713", "\u2717", "Read", "\u2717", "\u2713"],
        ["Agency Admin", "\u2713", "\u2713", "\u2717", "\u2717", "Full", "\u2717", "\u2717"],
        ["Basic User", "\u2713", "\u2717", "\u2717", "\u2717", "\u2717", "\u2717", "\u2717"],
    ]

    # Dimensions
    col_widths = [Inches(1.8), Inches(0.9), Inches(1.2), Inches(1.2), Inches(1.2),
                  Inches(1.0), Inches(1.0), Inches(1.1)]
    row_h = Inches(0.6)
    header_h = Inches(0.7)
    table_start_x = (SLIDE_WIDTH - sum(w for w in col_widths)) / 2
    table_start_y = Inches(1.5)

    # Draw header row
    x = table_start_x
    for i, header in enumerate(headers):
        cell = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, x, table_start_y,
                                       col_widths[i], header_h)
        cell.fill.solid()
        cell.fill.fore_color.rgb = DARK_NAVY
        cell.line.color.rgb = DARK_NAVY
        cell.line.width = Pt(0.5)

        tf = cell.text_frame
        tf.word_wrap = True
        tf.paragraphs[0].alignment = PP_ALIGN.CENTER
        p = tf.paragraphs[0]
        p.text = header
        p.font.size = Pt(11)
        p.font.color.rgb = LIME
        p.font.bold = True
        p.font.name = FONT_NAME
        tf.margin_top = Pt(6)
        tf.margin_bottom = Pt(6)
        x += col_widths[i]

    # Draw data rows
    for row_idx, row in enumerate(rows_data):
        x = table_start_x
        y = table_start_y + header_h + row_idx * row_h
        bg = WHITE if row_idx % 2 == 0 else GREY_100

        for col_idx, val in enumerate(row):
            cell = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, x, y,
                                           col_widths[col_idx], row_h)
            cell.fill.solid()
            cell.fill.fore_color.rgb = bg
            cell.line.color.rgb = GREY_300
            cell.line.width = Pt(0.5)

            tf = cell.text_frame
            tf.word_wrap = True
            p = tf.paragraphs[0]
            p.text = val
            p.font.size = Pt(12)
            p.font.name = FONT_NAME
            tf.margin_top = Pt(4)
            tf.margin_bottom = Pt(4)

            if col_idx == 0:
                p.font.color.rgb = DARK_NAVY
                p.font.bold = True
                p.alignment = PP_ALIGN.LEFT
                tf.margin_left = Pt(8)
            else:
                p.alignment = PP_ALIGN.CENTER
                if val == "\u2713":
                    p.font.color.rgb = RAG_GREEN
                    p.font.bold = True
                elif val == "\u2717":
                    p.font.color.rgb = RAG_RED
                elif val in ("Full", "Read"):
                    p.font.color.rgb = ACTIVE_BLUE
                    p.font.bold = True
                else:
                    p.font.color.rgb = DARK_NAVY

            x += col_widths[col_idx]

    # Auth info below table
    auth_y = table_start_y + header_h + len(rows_data) * row_h + Inches(0.6)
    add_textbox(slide, MARGIN_LEFT, auth_y, CONTENT_WIDTH, Inches(0.4),
                "Authentication & Security", font_size=16, color=TEAL, bold=True)

    add_bullet_list(slide, MARGIN_LEFT, auth_y + Inches(0.4), CONTENT_WIDTH, Inches(2.5),
        [
            "Azure AD / O365 SSO integration via MSAL — shared with CopyGenAI application",
            "Bearer token authentication on all API requests and WebSocket connections",
            "Agency-scoped data access — basic users only see their own agency's campaigns",
            "User Management screen (Super Admin only) — assign roles, agencies, view change history",
        ], font_size=13)


def make_tech_architecture_slide(prs):
    """Slide 23: Technical Architecture (layered diagram)."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, WHITE)

    add_textbox(slide, MARGIN_LEFT, Inches(0.3), CONTENT_WIDTH, Inches(0.6),
                "Technical Architecture", font_size=28, color=DARK_NAVY, bold=True)

    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, MARGIN_LEFT, Inches(0.85),
                                  Inches(1.5), Pt(3))
    bar.fill.solid()
    bar.fill.fore_color.rgb = ACTIVE_BLUE
    bar.line.fill.background()

    # Layer definitions
    layers = [
        ("Frontend", ACTIVE_BLUE, [
            ("React + TypeScript", Inches(2.5)),
            ("Tailwind CSS", Inches(1.8)),
            ("MSAL Auth", Inches(1.5)),
            ("WebSocket Client", Inches(2.0)),
            ("REST Client", Inches(1.6)),
        ]),
        ("Backend API", ELECTRIC_VIOLET, [
            ("FastAPI (Python)", Inches(2.5)),
            ("WebSocket /ws/analyze", Inches(2.3)),
            ("REST /api/*", Inches(1.8)),
            ("Analysis Service", Inches(2.0)),
        ]),
        ("AI Layer", TEAL, [
            ("Legal Agent", Inches(1.8)),
            ("Brand Agent", Inches(1.8)),
            ("Best Practices Agent", Inches(2.3)),
            ("Tech Specs Agent", Inches(2.0)),
            ("Lead Agent", Inches(1.6)),
        ]),
        ("Data Layer", DARK_NAVY, [
            ("PostgreSQL", Inches(2.0)),
            ("SQLAlchemy Async", Inches(2.2)),
            ("Alembic Migrations", Inches(2.2)),
            ("File Storage", Inches(1.8)),
        ]),
    ]

    layer_h = Inches(1.1)
    layer_gap = Inches(0.25)
    start_y = Inches(1.15)
    label_w = Inches(1.8)
    content_start_x = MARGIN_LEFT + label_w + Inches(0.2)
    # Reserve 2.6" on right for external service boxes
    ext_col_w = Inches(2.3)
    ext_gap = Inches(0.3)
    content_end_x = SLIDE_WIDTH - MARGIN_RIGHT - ext_col_w - ext_gap

    for layer_idx, (layer_name, color, components) in enumerate(layers):
        y = start_y + layer_idx * (layer_h + layer_gap)

        # Layer label
        add_rounded_rect(slide, MARGIN_LEFT, y, label_w, layer_h,
                         color, layer_name, font_size=13, font_color=WHITE, bold=True)

        # Components
        comp_gap = Inches(0.15)
        total_comp_w = sum(w for _, w in components) + (len(components) - 1) * comp_gap
        available_w = content_end_x - content_start_x
        scale = min(1.0, available_w / total_comp_w)

        cx = content_start_x
        for comp_name, comp_w in components:
            scaled_w = comp_w * scale
            add_rounded_rect(slide, cx, y + Inches(0.15), scaled_w, layer_h - Inches(0.3),
                             GREY_100, comp_name, font_size=11, font_color=DARK_NAVY,
                             bold=False, line_color=color)
            cx += scaled_w + comp_gap * scale

    # External services on the right (in reserved column)
    ext_x = SLIDE_WIDTH - MARGIN_RIGHT - ext_col_w
    # Position Azure AD aligned with Backend API row
    ext_y_azure = start_y + 1 * (layer_h + layer_gap) + Inches(0.15)
    add_rounded_rect(slide, ext_x, ext_y_azure, ext_col_w, layer_h - Inches(0.3),
                     DARK_NAVY, "Azure AD", font_size=12, font_color=LIME, bold=True)

    # Position Gemini aligned with AI Layer row
    ext_y_gemini = start_y + 2 * (layer_h + layer_gap) + Inches(0.15)
    add_rounded_rect(slide, ext_x, ext_y_gemini, ext_col_w, layer_h - Inches(0.3),
                     DARK_NAVY, "Google Gemini\n2.5 Flash", font_size=12,
                     font_color=LIME, bold=True)

    # Bottom note
    note_y = start_y + len(layers) * (layer_h + layer_gap) + Inches(0.1)
    add_textbox(slide, MARGIN_LEFT, note_y, CONTENT_WIDTH, Inches(0.8),
                "All communication secured via MSAL bearer tokens. "
                "Agents run in parallel via asyncio. "
                "Database uses async SQLAlchemy + asyncpg for non-blocking I/O.",
                font_size=12, color=GREY_700)


def make_closing_slide(prs):
    """Slide 24: Closing slide with logo."""
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    set_slide_bg(slide, DARK_NAVY)

    # Logo
    if LOGO_PATH.exists():
        slide.shapes.add_picture(
            str(LOGO_PATH),
            Inches(0.8), Inches(1.2),
            height=Inches(1.8)
        )

    # Accent bar
    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Inches(0.8), Inches(3.4),
                                  Inches(2.0), Pt(4))
    bar.fill.solid()
    bar.fill.fore_color.rgb = LIME
    bar.line.fill.background()

    tf = add_rich_textbox(slide, Inches(0.8), Inches(3.7), Inches(10), Inches(1.0))
    p = tf.paragraphs[0]
    run1 = p.add_run()
    run1.text = "Intelligent Review. "
    run1.font.size = Pt(32)
    run1.font.color.rgb = ELECTRIC_VIOLET
    run1.font.bold = True
    run1.font.name = FONT_NAME
    run2 = p.add_run()
    run2.text = "Confident Delivery."
    run2.font.size = Pt(32)
    run2.font.color.rgb = WHITE
    run2.font.bold = True
    run2.font.name = FONT_NAME

    add_textbox(slide, Inches(0.8), Inches(4.8), Inches(8), Inches(0.5),
                "AI-powered proof review for Barclays marketing materials",
                font_size=16, color=GREY_300)

    add_textbox(slide, Inches(0.8), Inches(5.6), Inches(6), Inches(0.5),
                "Built by OLIVER Agency", font_size=14, color=GREY_700)


# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------

def main():
    prs = Presentation()
    prs.slide_width = SLIDE_WIDTH
    prs.slide_height = SLIDE_HEIGHT

    # Slide 1: Title
    make_title_slide(prs)

    # Slide 2: Agenda
    make_agenda_slide(prs)

    # Slide 3: Section — The Challenge
    make_section_divider(prs, 1, "The Challenge",
                         "Why manual proof review doesn't scale")

    # Slide 4: Problem statement
    make_problem_slide(prs)

    # Slide 5: Section — Introducing Mod Comms
    make_section_divider(prs, 2, "Introducing Mod Comms",
                         "AI-powered proof review at a glance")

    # Slide 6: Solution overview
    make_solution_slide(prs)

    # Slide 7: Section — Multi-Agent AI System
    make_section_divider(prs, 3, "Multi-Agent AI System",
                         "Four specialist agents working in parallel")

    # Slide 8: Agent architecture diagram
    make_agent_architecture_slide(prs)

    # Slide 9: Legal Agent
    make_legal_agent_slide(prs)

    # Slide 10: Brand Agent
    make_brand_agent_slide(prs)

    # Slide 11: Channel Agents
    make_channel_agents_slide(prs)

    # Slide 12: RAG Status
    make_rag_status_slide(prs)

    # Slide 13: Section — Campaign Management
    make_section_divider(prs, 4, "Campaign Management",
                         "Organising and tracking marketing proofs")

    # Slide 14: Campaign lifecycle
    make_campaign_lifecycle_slide(prs)

    # Slide 15: Section — Real-Time Analysis
    make_section_divider(prs, 5, "Real-Time Analysis",
                         "Live WebSocket-powered proof review")

    # Slide 16: WebSocket analysis
    make_websocket_slide(prs)

    # Slide 17: Section — Feedback & Reporting
    make_section_divider(prs, 6, "Feedback & Reporting",
                         "Structured results and PDF export")

    # Slide 18: Feedback reports
    make_feedback_reports_slide(prs)

    # Slide 19: Section — Knowledge Base & Admin
    make_section_divider(prs, 7, "Knowledge Base & Admin",
                         "Managing guidelines, analytics, and access control")

    # Slide 20: Knowledge Base
    make_knowledge_base_slide(prs)

    # Slide 21: Analytics, Auditing, Settings
    make_admin_three_col_slide(prs)

    # Slide 22: User Roles
    make_user_roles_slide(prs)

    # Slide 23: Section — Technical Architecture
    make_section_divider(prs, 8, "Technical Architecture",
                         "How it all fits together")

    # Slide 24: Tech Architecture
    make_tech_architecture_slide(prs)

    # Slide 25: Closing
    make_closing_slide(prs)

    # Save
    prs.save(str(OUTPUT_PPTX))
    print(f"Presentation saved to: {OUTPUT_PPTX}")
    print(f"Total slides: {len(prs.slides)}")


if __name__ == "__main__":
    main()
