#!/usr/bin/env python3
"""Build an editable PPTX demo day poster for doany.ai Agent Eval Pipeline."""

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
import math

# ──── Colors ────
BG_DARK = RGBColor(0x0A, 0x0E, 0x1A)
CARD_BG = RGBColor(0x11, 0x18, 0x2A)
CYAN = RGBColor(0x38, 0xBD, 0xF8)
TEAL = RGBColor(0x06, 0xB6, 0xD4)
PURPLE = RGBColor(0xA7, 0x8B, 0xFA)
GREEN = RGBColor(0x34, 0xD3, 0x99)
ORANGE = RGBColor(0xFB, 0x92, 0x3C)
PINK = RGBColor(0xF4, 0x72, 0xB6)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
LIGHT_GRAY = RGBColor(0x94, 0xA3, 0xB8)
DIM_GRAY = RGBColor(0x64, 0x74, 0x8B)
DARK_CARD = RGBColor(0x0F, 0x17, 0x2A)

STAGE_COLORS = [CYAN, PURPLE, GREEN, ORANGE]
SCORE_COLORS = [CYAN, PURPLE, GREEN, ORANGE, PINK]


def add_rounded_rect(slide, left, top, width, height, fill_color, border_color=None, border_width=Pt(1)):
    """Add a rounded rectangle shape."""
    shape = slide.shapes.add_shape(
        MSO_SHAPE.ROUNDED_RECTANGLE, left, top, width, height
    )
    shape.fill.solid()
    shape.fill.fore_color.rgb = fill_color
    if border_color:
        shape.line.color.rgb = border_color
        shape.line.width = border_width
    else:
        shape.line.fill.background()
    # Smaller corner rounding
    shape.adjustments[0] = 0.05
    return shape


def add_text_box(slide, left, top, width, height, text, font_size=18,
                 color=WHITE, bold=False, alignment=PP_ALIGN.LEFT,
                 font_name="Calibri"):
    """Add a text box with specified formatting."""
    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
    return txBox


def add_multiline_text(slide, left, top, width, height, lines):
    """Add text box with multiple styled lines.
    lines: list of (text, font_size, color, bold, alignment)
    """
    txBox = slide.shapes.add_textbox(left, top, width, height)
    tf = txBox.text_frame
    tf.word_wrap = True
    for i, (text, font_size, color, bold, alignment) in enumerate(lines):
        if i == 0:
            p = tf.paragraphs[0]
        else:
            p = tf.add_paragraph()
        p.text = text
        p.font.size = Pt(font_size)
        p.font.color.rgb = color
        p.font.bold = bold
        p.font.name = "Calibri"
        p.alignment = alignment
        p.space_after = Pt(4)
    return txBox


def build_poster():
    prs = Presentation()
    # 48 x 36 inches landscape
    prs.slide_width = Inches(48)
    prs.slide_height = Inches(36)

    slide = prs.slides.add_slide(prs.slide_layouts[6])  # Blank

    # ══════════════════════════════════════════════
    # BACKGROUND
    # ══════════════════════════════════════════════
    bg = slide.background
    fill = bg.fill
    fill.solid()
    fill.fore_color.rgb = BG_DARK

    # ══════════════════════════════════════════════
    # HEADER BAR
    # ══════════════════════════════════════════════
    header = add_rounded_rect(slide, Inches(0.6), Inches(0.5), Inches(46.8), Inches(4.5),
                              CARD_BG, border_color=RGBColor(0x1E, 0x3A, 0x5F))
    # Accent line at top
    accent_line = slide.shapes.add_shape(
        MSO_SHAPE.RECTANGLE, Inches(0.6), Inches(0.5), Inches(46.8), Inches(0.08)
    )
    accent_line.fill.solid()
    accent_line.fill.fore_color.rgb = TEAL
    accent_line.line.fill.background()

    # Logo
    add_text_box(slide, Inches(1.2), Inches(0.9), Inches(8), Inches(1),
                 "doany.ai", font_size=42, color=TEAL, bold=True)

    # Title
    add_text_box(slide, Inches(1.2), Inches(2.0), Inches(28), Inches(2),
                 "Agent Eval Pipeline", font_size=72, color=WHITE, bold=True)

    # Subtitle
    add_text_box(slide, Inches(1.2), Inches(3.8), Inches(28), Inches(1),
                 "Automated Discovery, Testing & Publishing for 850+ AI Agent Skills",
                 font_size=28, color=LIGHT_GRAY)

    # Header stat boxes
    stat_data = [("850+", "SKILLS"), ("87%", "CORRECTNESS"), ("<2m", "PUBLISH")]
    stat_colors = [CYAN, GREEN, ORANGE]
    for i, (num, label) in enumerate(stat_data):
        sx = Inches(36.5 + i * 3.8)
        sy = Inches(1.2)
        box = add_rounded_rect(slide, sx, sy, Inches(3.2), Inches(2.8),
                               RGBColor(0x0D, 0x14, 0x26),
                               border_color=RGBColor(0x1E, 0x3A, 0x5F))
        add_text_box(slide, sx, sy + Inches(0.3), Inches(3.2), Inches(1.5),
                     num, font_size=44, color=stat_colors[i], bold=True,
                     alignment=PP_ALIGN.CENTER)
        add_text_box(slide, sx, sy + Inches(1.7), Inches(3.2), Inches(0.6),
                     label, font_size=14, color=DIM_GRAY, bold=True,
                     alignment=PP_ALIGN.CENTER)

    # ══════════════════════════════════════════════
    # PIPELINE SECTION (full width)
    # ══════════════════════════════════════════════
    pipe_y = Inches(5.4)
    pipe_card = add_rounded_rect(slide, Inches(0.6), pipe_y, Inches(46.8), Inches(10.8),
                                  CARD_BG, border_color=RGBColor(0x1E, 0x3A, 0x5F))

    add_text_box(slide, Inches(1.4), pipe_y + Inches(0.4), Inches(10), Inches(0.6),
                 "THE PIPELINE", font_size=16, color=TEAL, bold=True)

    stages = [
        ("01", "DISCOVER", "Crawl registries & build\nunified skill catalog", ["GitHub", "skills.sh", "Community"]),
        ("02", "ANALYZE", "Parse SKILL.md, classify\n& score complexity", ["Metadata", "Dependencies"]),
        ("03", "EVALUATE", "Sandbox test in Claude Code\n& capture metrics", ["3,200+ Scenarios", "5D Scoring"]),
        ("04", "PUBLISH", "Push to CDN & update\nsearch index in <2 min", ["Vercel Blob", "Embed Cards"]),
    ]

    stage_w = Inches(9.5)
    stage_gap = Inches(1.8)
    start_x = Inches(2.5)
    icon_y = pipe_y + Inches(1.6)

    for i, (num, name, desc, tags) in enumerate(stages):
        col = STAGE_COLORS[i]
        sx = start_x + i * (stage_w + stage_gap)

        # Stage icon background
        icon_bg = add_rounded_rect(slide, sx + Inches(3.2), icon_y, Inches(2.2), Inches(2.2),
                                    RGBColor(0x0D, 0x14, 0x26), border_color=col, border_width=Pt(3))
        # Icon placeholder circle
        icon_circle = slide.shapes.add_shape(
            MSO_SHAPE.OVAL, sx + Inches(3.65), icon_y + Inches(0.45), Inches(1.3), Inches(1.3)
        )
        icon_circle.fill.solid()
        icon_circle.fill.fore_color.rgb = RGBColor(0x0D, 0x14, 0x26)
        icon_circle.line.color.rgb = col
        icon_circle.line.width = Pt(3)
        # Icon text (number)
        add_text_box(slide, sx + Inches(3.65), icon_y + Inches(0.6), Inches(1.3), Inches(1.0),
                     num, font_size=32, color=col, bold=True, alignment=PP_ALIGN.CENTER)

        # Stage name
        add_text_box(slide, sx, icon_y + Inches(2.6), stage_w, Inches(0.8),
                     name, font_size=32, color=col, bold=True, alignment=PP_ALIGN.CENTER)

        # Description
        add_text_box(slide, sx + Inches(1.2), icon_y + Inches(3.5), stage_w - Inches(2.4), Inches(1.5),
                     desc, font_size=18, color=LIGHT_GRAY, alignment=PP_ALIGN.CENTER)

        # Tags
        tag_x_start = sx + Inches(1.8)
        for j, tag in enumerate(tags):
            tw = Inches(len(tag) * 0.17 + 0.5)
            tag_box = add_rounded_rect(slide, tag_x_start + j * (tw + Inches(0.2)),
                                        icon_y + Inches(5.4), tw, Inches(0.55),
                                        RGBColor(0x0D, 0x14, 0x26), border_color=col)
            add_text_box(slide, tag_x_start + j * (tw + Inches(0.2)),
                         icon_y + Inches(5.4), tw, Inches(0.55),
                         tag, font_size=13, color=col, bold=True, alignment=PP_ALIGN.CENTER)

        # Arrow between stages (except after last)
        if i < 3:
            arrow_x = sx + stage_w + Inches(0.2)
            arrow = slide.shapes.add_shape(
                MSO_SHAPE.RIGHT_ARROW, arrow_x, icon_y + Inches(3.0),
                Inches(1.4), Inches(0.6)
            )
            arrow.fill.solid()
            # Blend color between this stage and next
            # Blend color between current and next stage
            c1 = (col[0], col[1], col[2])
            c2 = (STAGE_COLORS[i+1][0], STAGE_COLORS[i+1][1], STAGE_COLORS[i+1][2])
            arrow.fill.fore_color.rgb = RGBColor(
                (c1[0] + c2[0]) // 2,
                (c1[1] + c2[1]) // 2,
                (c1[2] + c2[2]) // 2,
            )
            arrow.line.fill.background()
            arrow.rotation = 0.0

    # ══════════════════════════════════════════════
    # BOTTOM ROW: Three columns
    # ══════════════════════════════════════════════
    bot_y = Inches(16.6)
    col_h = Inches(13.8)
    col1_w = Inches(16)
    col23_w = Inches(14.8)

    # ─── COLUMN 1: KEY METRICS ───
    metrics_card = add_rounded_rect(slide, Inches(0.6), bot_y, col1_w, col_h,
                                     CARD_BG, border_color=RGBColor(0x1E, 0x3A, 0x5F))
    add_text_box(slide, Inches(1.4), bot_y + Inches(0.4), Inches(10), Inches(0.6),
                 "KEY METRICS", font_size=16, color=TEAL, bold=True)

    metrics = [
        ("850+", "Skills Indexed", CYAN),
        ("3,200+", "Eval Scenarios", PURPLE),
        ("~45m", "Full Pipeline", GREEN),
        ("<2m", "Publish Latency", ORANGE),
    ]
    m_cols = 2
    m_w = Inches(6.8)
    m_h = Inches(3.6)
    m_gap = Inches(0.35)
    m_start_x = Inches(1.2)
    m_start_y = bot_y + Inches(1.4)

    for idx, (num, label, color) in enumerate(metrics):
        r = idx // m_cols
        c = idx % m_cols
        mx = m_start_x + c * (m_w + m_gap)
        my = m_start_y + r * (m_h + m_gap)

        m_box = add_rounded_rect(slide, mx, my, m_w, m_h,
                                  RGBColor(0x0D, 0x14, 0x26),
                                  border_color=RGBColor(0x1E, 0x3A, 0x5F))
        # Top accent
        m_accent = slide.shapes.add_shape(
            MSO_SHAPE.RECTANGLE, mx, my, m_w, Inches(0.06)
        )
        m_accent.fill.solid()
        m_accent.fill.fore_color.rgb = color
        m_accent.line.fill.background()

        add_text_box(slide, mx, my + Inches(0.5), m_w, Inches(2),
                     num, font_size=52, color=color, bold=True, alignment=PP_ALIGN.CENTER)
        add_text_box(slide, mx, my + Inches(2.3), m_w, Inches(0.8),
                     label, font_size=16, color=DIM_GRAY, bold=True, alignment=PP_ALIGN.CENTER)

    # Hero metric (full width)
    hero_y = m_start_y + 2 * (m_h + m_gap)
    hero_box = add_rounded_rect(slide, m_start_x, hero_y, Inches(14), Inches(4.4),
                                 RGBColor(0x0A, 0x1A, 0x1A),
                                 border_color=GREEN, border_width=Pt(2))
    hero_accent = slide.shapes.add_shape(
        MSO_SHAPE.RECTANGLE, m_start_x, hero_y, Inches(14), Inches(0.06)
    )
    hero_accent.fill.solid()
    hero_accent.fill.fore_color.rgb = GREEN
    hero_accent.line.fill.background()

    add_text_box(slide, m_start_x, hero_y + Inches(0.6), Inches(14), Inches(2.5),
                 "87%", font_size=72, color=GREEN, bold=True, alignment=PP_ALIGN.CENTER)
    add_text_box(slide, m_start_x, hero_y + Inches(3.0), Inches(14), Inches(0.8),
                 "AVERAGE CORRECTNESS SCORE", font_size=16, color=DIM_GRAY, bold=True,
                 alignment=PP_ALIGN.CENTER)

    # ─── COLUMN 2: 5D SCORING (RADAR) ───
    col2_x = Inches(17)
    radar_card = add_rounded_rect(slide, col2_x, bot_y, col23_w, col_h,
                                   CARD_BG, border_color=RGBColor(0x1E, 0x3A, 0x5F))
    add_text_box(slide, col2_x + Inches(0.6), bot_y + Inches(0.4), Inches(12), Inches(0.6),
                 "5-DIMENSIONAL SCORING", font_size=16, color=TEAL, bold=True)

    # Build radar chart with shapes
    radar_cx = col2_x + col23_w / 2
    radar_cy = bot_y + Inches(6.5)
    radar_r = Inches(4.0)

    # Draw pentagon axes & labels
    dims = [
        ("CORRECTNESS", "87%", "Meets specification", CYAN),
        ("COMPLETENESS", "82%", "All deliverables present", PURPLE),
        ("QUALITY", "85%", "Production-grade output", GREEN),
        ("EFFICIENCY", "78%", "Token & tool economy", ORANGE),
        ("SAFETY", "91%", "No leaks or destructive ops", PINK),
    ]
    scores = [0.87, 0.82, 0.85, 0.78, 0.91]

    for i, (name, pct, desc, color) in enumerate(dims):
        angle = math.radians(-90 + i * 72)
        # Axis endpoint
        ex = radar_cx + int(radar_r * math.cos(angle))
        ey = radar_cy + int(radar_r * math.sin(angle))

        # Axis line (using thin rectangle)
        line = slide.shapes.add_connector(1, radar_cx, radar_cy, ex, ey)  # type 1 = straight
        line.line.color.rgb = RGBColor(0x1E, 0x3A, 0x5F)
        line.line.width = Pt(1)

        # Label position
        label_r = radar_r + Inches(0.8)
        lx = radar_cx + int(label_r * math.cos(angle)) - Inches(1.5)
        ly = radar_cy + int(label_r * math.sin(angle)) - Inches(0.4)

        add_multiline_text(slide, lx, ly, Inches(3), Inches(1.2), [
            (name, 16, color, True, PP_ALIGN.CENTER),
            (pct, 28, color, True, PP_ALIGN.CENTER),
        ])

        # Data point (circle at score distance)
        dp_r = Inches(0.18)
        dp_x = radar_cx + int(radar_r * scores[i] * math.cos(angle)) - dp_r
        dp_y = radar_cy + int(radar_r * scores[i] * math.sin(angle)) - dp_r
        dot = slide.shapes.add_shape(MSO_SHAPE.OVAL, dp_x, dp_y, dp_r * 2, dp_r * 2)
        dot.fill.solid()
        dot.fill.fore_color.rgb = color
        dot.line.fill.background()

    # Legend at bottom
    legend_y = bot_y + Inches(11.5)
    for i, (name, pct, desc, color) in enumerate(dims):
        r = i // 2
        c = i % 2
        lx = col2_x + Inches(1) + c * Inches(7)
        ly = legend_y + r * Inches(0.7)

        # Dot
        dot = slide.shapes.add_shape(MSO_SHAPE.OVAL, lx, ly + Inches(0.08), Inches(0.18), Inches(0.18))
        dot.fill.solid()
        dot.fill.fore_color.rgb = color
        dot.line.fill.background()

        add_text_box(slide, lx + Inches(0.35), ly, Inches(6), Inches(0.5),
                     desc, font_size=14, color=LIGHT_GRAY)

    # ─── COLUMN 3: DIFFERENTIATORS ───
    col3_x = Inches(32.2)
    diff_card = add_rounded_rect(slide, col3_x, bot_y, col23_w, col_h,
                                  CARD_BG, border_color=RGBColor(0x1E, 0x3A, 0x5F))
    add_text_box(slide, col3_x + Inches(0.6), bot_y + Inches(0.4), Inches(12), Inches(0.6),
                 "WHAT MAKES IT UNIQUE", font_size=16, color=TEAL, bold=True)

    diffs = [
        ("Multi-Source Auto-Discovery", "No manual curation — crawls &\ndeduplicates across registries", CYAN),
        ("Sandboxed Claude Code Eval", "Real isolated sessions with\nfull tool-call capture", PURPLE),
        ("Continuous Re-Evaluation", "Auto-retests as models improve\n— always fresh scores", GREEN),
        ("CDN-First <2 min Publishing", "Vercel Blob push with instant\nsearch index updates", ORANGE),
        ("Embed-Ready Partner Cards", "Drop-in integration for\npartner ecosystems", PINK),
    ]

    diff_y = bot_y + Inches(1.4)
    diff_h = Inches(2.2)
    diff_gap = Inches(0.3)

    for i, (title, desc, color) in enumerate(diffs):
        dy = diff_y + i * (diff_h + diff_gap)

        # Item background
        item_bg = add_rounded_rect(slide, col3_x + Inches(0.5), dy,
                                    Inches(13.6), diff_h,
                                    RGBColor(0x0D, 0x14, 0x26))
        # Left accent bar
        accent = slide.shapes.add_shape(
            MSO_SHAPE.RECTANGLE, col3_x + Inches(0.5), dy, Inches(0.08), diff_h
        )
        accent.fill.solid()
        accent.fill.fore_color.rgb = color
        accent.line.fill.background()

        # Icon circle
        ic = slide.shapes.add_shape(
            MSO_SHAPE.OVAL, col3_x + Inches(1.0), dy + Inches(0.35),
            Inches(1.4), Inches(1.4)
        )
        ic.fill.solid()
        ic.fill.fore_color.rgb = RGBColor(
            min(color[0] // 5, 40), min(color[1] // 5, 40), min(color[2] // 5, 40)
        )
        ic.line.color.rgb = color
        ic.line.width = Pt(2)

        # Number inside icon
        add_text_box(slide, col3_x + Inches(1.0), dy + Inches(0.55),
                     Inches(1.4), Inches(1.0),
                     str(i + 1), font_size=28, color=color, bold=True,
                     alignment=PP_ALIGN.CENTER)

        # Title
        add_text_box(slide, col3_x + Inches(2.8), dy + Inches(0.25),
                     Inches(10), Inches(0.7),
                     title, font_size=20, color=WHITE, bold=True)
        # Description
        add_text_box(slide, col3_x + Inches(2.8), dy + Inches(1.0),
                     Inches(10), Inches(1.0),
                     desc, font_size=15, color=LIGHT_GRAY)

    # ══════════════════════════════════════════════
    # FOOTER
    # ══════════════════════════════════════════════
    footer_y = Inches(30.8)
    footer = add_rounded_rect(slide, Inches(0.6), footer_y, Inches(46.8), Inches(2.2),
                               CARD_BG, border_color=RGBColor(0x1E, 0x3A, 0x5F))

    team = [
        ("AC", "Alex Chen", "Pipeline Lead", CYAN),
        ("JP", "Jordan Park", "Eval Framework", PURPLE),
        ("SL", "Sam Liu", "Frontend & Publishing", GREEN),
    ]

    for i, (initials, name, role, color) in enumerate(team):
        tx = Inches(2) + i * Inches(7)
        # Avatar circle
        av = slide.shapes.add_shape(
            MSO_SHAPE.OVAL, tx, footer_y + Inches(0.5), Inches(1.1), Inches(1.1)
        )
        av.fill.solid()
        av.fill.fore_color.rgb = color
        av.line.fill.background()
        add_text_box(slide, tx, footer_y + Inches(0.6), Inches(1.1), Inches(0.9),
                     initials, font_size=18, color=WHITE, bold=True,
                     alignment=PP_ALIGN.CENTER)
        add_text_box(slide, tx + Inches(1.4), footer_y + Inches(0.45), Inches(5), Inches(0.5),
                     name, font_size=18, color=WHITE, bold=True)
        add_text_box(slide, tx + Inches(1.4), footer_y + Inches(1.1), Inches(5), Inches(0.5),
                     role, font_size=13, color=DIM_GRAY)

    # doany.ai URL
    add_text_box(slide, Inches(36), footer_y + Inches(0.3), Inches(10), Inches(1),
                 "doany.ai", font_size=28, color=CYAN, bold=True, alignment=PP_ALIGN.RIGHT)
    add_text_box(slide, Inches(36), footer_y + Inches(1.3), Inches(10), Inches(0.6),
                 "Demo Day — April 2026", font_size=14, color=DIM_GRAY,
                 alignment=PP_ALIGN.RIGHT)

    # ══════════════════════════════════════════════
    # SAVE
    # ══════════════════════════════════════════════
    output_path = "poster_output/doany_agent_eval_pipeline.pptx"
    prs.save(output_path)
    print(f"✅ PPTX saved to {output_path}")
    print(f"   Slide size: 48×36 inches (landscape)")
    print(f"   All shapes are editable in PowerPoint")


if __name__ == "__main__":
    build_poster()
