#!/usr/bin/env python3
"""Generate API Outage Post-Incident Review deck for doany.ai leadership."""

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 os

# ── Theme constants ──────────────────────────────────────────────────────────
BG_DARK    = RGBColor(0x0A, 0x0E, 0x1A)   # deep navy-black
BG_CARD    = RGBColor(0x12, 0x18, 0x2A)   # slightly lighter card bg
ACCENT     = RGBColor(0x00, 0xB4, 0xFF)   # electric blue accent
RED        = RGBColor(0xFF, 0x3B, 0x3B)   # severity red
AMBER      = RGBColor(0xFF, 0xA5, 0x00)   # amber/warning
GREEN      = RGBColor(0x00, 0xD6, 0x8F)   # success green
WHITE      = RGBColor(0xFF, 0xFF, 0xFF)
LIGHT_GRAY = RGBColor(0xA0, 0xAD, 0xC0)
MED_GRAY   = RGBColor(0x5A, 0x6A, 0x80)
DIVIDER    = RGBColor(0x1E, 0x28, 0x3C)

SLIDE_W = Inches(13.333)
SLIDE_H = Inches(7.5)

prs = Presentation()
prs.slide_width  = SLIDE_W
prs.slide_height = SLIDE_H

# ── Helpers ──────────────────────────────────────────────────────────────────
def set_bg(slide, color):
    bg = slide.background
    fill = bg.fill
    fill.solid()
    fill.fore_color.rgb = color

def add_rect(slide, left, top, width, height, color, alpha=None):
    shape = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, left, top, width, height)
    shape.fill.solid()
    shape.fill.fore_color.rgb = color
    shape.line.fill.background()
    if alpha is not None:
        # Set transparency via XML
        from pptx.oxml.ns import qn
        solidFill = shape.fill._fill
        srgb = solidFill.find(qn('a:solidFill')).find(qn('a:srgbClr'))
        if srgb is not None:
            alpha_el = srgb.makeelement(qn('a:alpha'), {'val': str(int(alpha * 1000))})
            srgb.append(alpha_el)
    return shape

def add_text(slide, left, top, width, height, text, font_size=18, color=WHITE,
             bold=False, alignment=PP_ALIGN.LEFT, font_name='Calibri'):
    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_accent_line(slide, left, top, width, color=ACCENT):
    shape = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, left, top, width, Pt(3))
    shape.fill.solid()
    shape.fill.fore_color.rgb = color
    shape.line.fill.background()
    return shape

def add_multi_text(slide, left, top, width, height, lines, default_size=16, default_color=WHITE):
    """lines: list of (text, size, color, bold, alignment)"""
    txBox = slide.shapes.add_textbox(left, top, width, height)
    tf = txBox.text_frame
    tf.word_wrap = True
    for i, item in enumerate(lines):
        text = item[0]
        size = item[1] if len(item) > 1 else default_size
        color = item[2] if len(item) > 2 else default_color
        bold = item[3] if len(item) > 3 else False
        align = item[4] if len(item) > 4 else PP_ALIGN.LEFT
        if i == 0:
            p = tf.paragraphs[0]
        else:
            p = tf.add_paragraph()
        p.text = text
        p.font.size = Pt(size)
        p.font.color.rgb = color
        p.font.bold = bold
        p.font.name = 'Calibri'
        p.alignment = align
        p.space_after = Pt(4)
    return txBox


# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 1 — Title
# ═══════════════════════════════════════════════════════════════════════════════
slide = prs.slides.add_slide(prs.slide_layouts[6])  # blank
set_bg(slide, BG_DARK)

# Top accent bar
add_rect(slide, Inches(0), Inches(0), SLIDE_W, Pt(4), ACCENT)

# Subtle side accent stripe
add_rect(slide, Inches(0.8), Inches(2.4), Pt(5), Inches(2.6), ACCENT)

add_text(slide, Inches(1.2), Inches(2.5), Inches(10), Inches(0.9),
         "API OUTAGE", 52, WHITE, True)
add_text(slide, Inches(1.2), Inches(3.2), Inches(10), Inches(0.7),
         "Post-Incident Review", 36, ACCENT, False)

add_accent_line(slide, Inches(1.2), Inches(4.1), Inches(2.5))

add_multi_text(slide, Inches(1.2), Inches(4.4), Inches(6), Inches(1.2), [
    ("doany.ai  |  April 9, 2026", 18, LIGHT_GRAY, False),
    ("Leadership Review \u2014 Confidential", 16, MED_GRAY, False),
])

# Bottom-right badge
add_rect(slide, Inches(10.5), Inches(6.2), Inches(2.3), Inches(0.6), RGBColor(0xFF, 0x3B, 0x3B))
add_text(slide, Inches(10.5), Inches(6.25), Inches(2.3), Inches(0.5),
         "SEV-1 INCIDENT", 16, WHITE, True, PP_ALIGN.CENTER)


# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 2 — Incident Timeline
# ═══════════════════════════════════════════════════════════════════════════════
slide = prs.slides.add_slide(prs.slide_layouts[6])
set_bg(slide, BG_DARK)
add_rect(slide, Inches(0), Inches(0), SLIDE_W, Pt(4), ACCENT)

add_text(slide, Inches(0.8), Inches(0.4), Inches(5), Inches(0.5),
         "INCIDENT TIMELINE", 14, ACCENT, True)
add_text(slide, Inches(0.8), Inches(0.8), Inches(10), Inches(0.6),
         "April 9, 2026 \u2014 Detection to Full Recovery", 28, WHITE, True)
add_accent_line(slide, Inches(0.8), Inches(1.45), Inches(3))

# Timeline horizontal line
timeline_y = Inches(3.8)
add_rect(slide, Inches(1.0), timeline_y, Inches(11.3), Pt(2), MED_GRAY)

events = [
    ("02:14 UTC", "Anomaly\nDetected", RED, 1.0),
    ("02:22 UTC", "Alerts\nFired", AMBER, 3.2),
    ("02:35 UTC", "Incident\nDeclared", AMBER, 5.3),
    ("03:10 UTC", "Root Cause\nIdentified", ACCENT, 7.3),
    ("03:45 UTC", "Fix\nDeployed", GREEN, 9.3),
    ("04:12 UTC", "Full Recovery\nConfirmed", GREEN, 11.3),
]

for time_str, label, color, x in events:
    cx = Inches(x)
    # Dot on timeline
    dot = slide.shapes.add_shape(MSO_SHAPE.OVAL, cx - Pt(7), timeline_y - Pt(7), Pt(16), Pt(16))
    dot.fill.solid()
    dot.fill.fore_color.rgb = color
    dot.line.fill.background()

    # Time above
    add_text(slide, cx - Inches(0.55), timeline_y - Inches(1.2), Inches(1.2), Inches(0.4),
             time_str, 13, color, True, PP_ALIGN.CENTER)
    # Label below
    add_text(slide, cx - Inches(0.55), timeline_y + Inches(0.35), Inches(1.2), Inches(0.6),
             label, 12, LIGHT_GRAY, False, PP_ALIGN.CENTER)

# Duration callouts
add_rect(slide, Inches(1.0), Inches(5.6), Inches(3.5), Inches(1.1), BG_CARD)
add_multi_text(slide, Inches(1.2), Inches(5.7), Inches(3), Inches(0.9), [
    ("Time to Detect", 11, MED_GRAY, False),
    ("8 minutes", 22, AMBER, True),
])

add_rect(slide, Inches(5.0), Inches(5.6), Inches(3.5), Inches(1.1), BG_CARD)
add_multi_text(slide, Inches(5.2), Inches(5.7), Inches(3), Inches(0.9), [
    ("Time to Mitigate", 11, MED_GRAY, False),
    ("1h 31m", 22, RED, True),
])

add_rect(slide, Inches(9.0), Inches(5.6), Inches(3.5), Inches(1.1), BG_CARD)
add_multi_text(slide, Inches(9.2), Inches(5.7), Inches(3), Inches(0.9), [
    ("Total Duration", 11, MED_GRAY, False),
    ("1h 58m", 22, WHITE, True),
])


# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 3 — Business Impact
# ═══════════════════════════════════════════════════════════════════════════════
slide = prs.slides.add_slide(prs.slide_layouts[6])
set_bg(slide, BG_DARK)
add_rect(slide, Inches(0), Inches(0), SLIDE_W, Pt(4), ACCENT)

add_text(slide, Inches(0.8), Inches(0.4), Inches(5), Inches(0.5),
         "BUSINESS IMPACT", 14, RED, True)
add_text(slide, Inches(0.8), Inches(0.8), Inches(10), Inches(0.6),
         "Customer & Revenue Impact Assessment", 28, WHITE, True)
add_accent_line(slide, Inches(0.8), Inches(1.45), Inches(3), RED)

# Metric cards — row 1
cards_r1 = [
    ("TOTAL DOWNTIME", "~2 hours", "02:14 \u2013 04:12 UTC", RED),
    ("AFFECTED ENDPOINTS", "14 / 22", "63% of API surface", AMBER),
    ("FAILED REQUESTS", "~1.2M", "During incident window", RED),
]

for i, (title, value, sub, color) in enumerate(cards_r1):
    x = Inches(0.8 + i * 4.1)
    add_rect(slide, x, Inches(2.0), Inches(3.7), Inches(2.0), BG_CARD)
    add_rect(slide, x, Inches(2.0), Inches(3.7), Pt(3), color)
    add_text(slide, x + Inches(0.25), Inches(2.2), Inches(3.2), Inches(0.35),
             title, 11, MED_GRAY, True)
    add_text(slide, x + Inches(0.25), Inches(2.7), Inches(3.2), Inches(0.6),
             value, 36, color, True)
    add_text(slide, x + Inches(0.25), Inches(3.4), Inches(3.2), Inches(0.35),
             sub, 13, LIGHT_GRAY, False)

# Metric cards — row 2
cards_r2 = [
    ("AFFECTED CUSTOMERS", "~3,400", "Enterprise & growth tiers", AMBER),
    ("EST. REVENUE IMPACT", "$84K", "Based on avg. API transaction value", RED),
    ("SLA BREACH", "YES \u2014 99.9% target", "Monthly uptime now at 99.72%", RED),
]

for i, (title, value, sub, color) in enumerate(cards_r2):
    x = Inches(0.8 + i * 4.1)
    add_rect(slide, x, Inches(4.4), Inches(3.7), Inches(2.0), BG_CARD)
    add_rect(slide, x, Inches(4.4), Inches(3.7), Pt(3), color)
    add_text(slide, x + Inches(0.25), Inches(4.6), Inches(3.2), Inches(0.35),
             title, 11, MED_GRAY, True)
    add_text(slide, x + Inches(0.25), Inches(5.1), Inches(3.2), Inches(0.6),
             value, 36, color, True)
    add_text(slide, x + Inches(0.25), Inches(5.8), Inches(3.2), Inches(0.35),
             sub, 13, LIGHT_GRAY, False)


# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 4 — Root Cause Analysis
# ═══════════════════════════════════════════════════════════════════════════════
slide = prs.slides.add_slide(prs.slide_layouts[6])
set_bg(slide, BG_DARK)
add_rect(slide, Inches(0), Inches(0), SLIDE_W, Pt(4), ACCENT)

add_text(slide, Inches(0.8), Inches(0.4), Inches(5), Inches(0.5),
         "ROOT CAUSE ANALYSIS", 14, ACCENT, True)
add_text(slide, Inches(0.8), Inches(0.8), Inches(10), Inches(0.6),
         "Cascading Failure from Misconfigured Rate Limiter", 28, WHITE, True)
add_accent_line(slide, Inches(0.8), Inches(1.45), Inches(3))

# Cause chain — visual flow boxes
chain = [
    ("1. TRIGGER", "Rate limiter config deployed\nto prod without staged rollout", RED),
    ("2. PROPAGATION", "Malformed rules rejected by\nAPI gateway sidecar proxies", AMBER),
    ("3. CASCADE", "Gateway nodes entered crash-\nloop; 63% of endpoints down", RED),
    ("4. AMPLIFICATION", "Retry storms from clients\noverwhelmed remaining nodes", RED),
]

for i, (step, desc, color) in enumerate(chain):
    x = Inches(0.8 + i * 3.1)
    # Card
    add_rect(slide, x, Inches(2.1), Inches(2.8), Inches(2.2), BG_CARD)
    add_rect(slide, x, Inches(2.1), Inches(2.8), Pt(3), color)
    add_text(slide, x + Inches(0.2), Inches(2.3), Inches(2.4), Inches(0.35),
             step, 12, color, True)
    add_text(slide, x + Inches(0.2), Inches(2.8), Inches(2.4), Inches(1.2),
             desc, 14, LIGHT_GRAY, False)
    # Arrow between cards
    if i < 3:
        ax = x + Inches(2.9)
        add_text(slide, ax, Inches(2.8), Inches(0.3), Inches(0.5),
                 "\u25B6", 20, MED_GRAY, False, PP_ALIGN.CENTER)

# Contributing factors
add_rect(slide, Inches(0.8), Inches(4.8), Inches(11.7), Inches(2.0), BG_CARD)
add_text(slide, Inches(1.0), Inches(4.9), Inches(4), Inches(0.4),
         "CONTRIBUTING FACTORS", 12, ACCENT, True)

factors = [
    ("\u2022  No staged rollout gate for infrastructure config changes", LIGHT_GRAY),
    ("\u2022  Rate limiter config not covered by integration test suite", LIGHT_GRAY),
    ("\u2022  Circuit breakers not configured on inter-service calls", LIGHT_GRAY),
    ("\u2022  Client retry policy lacked exponential backoff / jitter", LIGHT_GRAY),
]
y_off = 5.35
for text, color in factors:
    add_text(slide, Inches(1.0), Inches(y_off), Inches(11), Inches(0.35),
             text, 14, color, False)
    y_off += 0.35


# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 5 — Remediation & Prevention
# ═══════════════════════════════════════════════════════════════════════════════
slide = prs.slides.add_slide(prs.slide_layouts[6])
set_bg(slide, BG_DARK)
add_rect(slide, Inches(0), Inches(0), SLIDE_W, Pt(4), ACCENT)

add_text(slide, Inches(0.8), Inches(0.4), Inches(5), Inches(0.5),
         "REMEDIATION & PREVENTION", 14, GREEN, True)
add_text(slide, Inches(0.8), Inches(0.8), Inches(10), Inches(0.6),
         "Immediate Response & Long-Term Safeguards", 28, WHITE, True)
add_accent_line(slide, Inches(0.8), Inches(1.45), Inches(3), GREEN)

# LEFT COLUMN — Immediate Fixes
add_rect(slide, Inches(0.8), Inches(1.9), Inches(5.7), Inches(5.0), BG_CARD)
add_rect(slide, Inches(0.8), Inches(1.9), Inches(5.7), Pt(3), GREEN)
add_text(slide, Inches(1.1), Inches(2.1), Inches(5), Inches(0.4),
         "IMMEDIATE FIXES  \u2714  APPLIED", 13, GREEN, True)

immediate = [
    ("\u2714  Rolled back rate limiter config to last known good", GREEN),
    ("\u2714  Restarted all affected API gateway pods", GREEN),
    ("\u2714  Added config validation pre-check to deploy pipeline", GREEN),
    ("\u2714  Enabled manual approval gate for infra config merges", GREEN),
    ("\u2714  Published customer-facing status page update", GREEN),
    ("\u2714  Issued proactive SLA breach notification to affected accounts", GREEN),
]
y_off = 2.7
for text, color in immediate:
    add_text(slide, Inches(1.1), Inches(y_off), Inches(5.2), Inches(0.4),
             text, 14, LIGHT_GRAY, False)
    y_off += 0.42

# RIGHT COLUMN — Long-Term Prevention
add_rect(slide, Inches(6.8), Inches(1.9), Inches(5.7), Inches(5.0), BG_CARD)
add_rect(slide, Inches(6.8), Inches(1.9), Inches(5.7), Pt(3), ACCENT)
add_text(slide, Inches(7.1), Inches(2.1), Inches(5), Inches(0.4),
         "LONG-TERM PREVENTION  \u2192  PLANNED", 13, ACCENT, True)

longterm = [
    ("\u25B8  Mandatory canary deployments for all config changes",),
    ("\u25B8  Rate limiter integration tests in CI/CD pipeline",),
    ("\u25B8  Circuit breakers on all inter-service communication",),
    ("\u25B8  Client SDK update: exponential backoff + jitter",),
    ("\u25B8  Enhanced monitoring: config drift detection alerts",),
    ("\u25B8  Quarterly game-day chaos engineering exercises",),
]
y_off = 2.7
for item in longterm:
    add_text(slide, Inches(7.1), Inches(y_off), Inches(5.2), Inches(0.4),
             item[0], 14, LIGHT_GRAY, False)
    y_off += 0.42


# ═══════════════════════════════════════════════════════════════════════════════
# SLIDE 6 — Action Items & Owners
# ═══════════════════════════════════════════════════════════════════════════════
slide = prs.slides.add_slide(prs.slide_layouts[6])
set_bg(slide, BG_DARK)
add_rect(slide, Inches(0), Inches(0), SLIDE_W, Pt(4), ACCENT)

add_text(slide, Inches(0.8), Inches(0.4), Inches(5), Inches(0.5),
         "ACTION ITEMS & OWNERS", 14, ACCENT, True)
add_text(slide, Inches(0.8), Inches(0.8), Inches(10), Inches(0.6),
         "Tracking to Closure", 28, WHITE, True)
add_accent_line(slide, Inches(0.8), Inches(1.45), Inches(3))

# Table header
col_x  = [0.8, 5.8, 8.6, 10.3, 11.6]
col_w  = [5.0, 2.8, 1.7, 1.3, 1.6]
headers = ["ACTION ITEM", "OWNER", "PRIORITY", "TARGET", "STATUS"]
header_y = Inches(1.9)

add_rect(slide, Inches(0.8), header_y, Inches(11.7), Inches(0.5), RGBColor(0x18, 0x20, 0x35))
for i, h in enumerate(headers):
    add_text(slide, Inches(col_x[i]), header_y + Pt(4), Inches(col_w[i]), Inches(0.4),
             h, 11, ACCENT, True)

rows = [
    ("Deploy automated canary pipeline",     "Engineering / Platform", "P0", "Apr 16", RED),
    ("Add rate-limiter integration tests",   "Engineering / QA",      "P0", "Apr 14", RED),
    ("Update incident runbook & playbook",   "SRE",                   "P1", "Apr 11", AMBER),
    ("Customer comms & post-mortem publish",  "Comms / CS",            "P1", "Apr 10", AMBER),
    ("SLA credit processing for affected",    "Finance / CS",          "P2", "Apr 17", LIGHT_GRAY),
]

for ri, (action, owner, priority, target, pcolor) in enumerate(rows):
    ry = Inches(2.5 + ri * 0.75)
    bg = BG_CARD if ri % 2 == 0 else BG_DARK
    add_rect(slide, Inches(0.8), ry, Inches(11.7), Inches(0.65), bg)
    # Priority color stripe on left
    add_rect(slide, Inches(0.8), ry, Pt(4), Inches(0.65), pcolor)

    vals = [action, owner, priority, target, "OPEN"]
    colors = [WHITE, LIGHT_GRAY, pcolor, LIGHT_GRAY, MED_GRAY]
    bolds  = [False, False, True, False, False]
    sizes  = [14, 13, 13, 13, 11]
    for i, v in enumerate(vals):
        add_text(slide, Inches(col_x[i]) + Pt(4), ry + Pt(6), Inches(col_w[i]), Inches(0.45),
                 v, sizes[i], colors[i], bolds[i])

# Footer note
add_text(slide, Inches(0.8), Inches(6.6), Inches(8), Inches(0.4),
         "Next review: April 14, 2026  |  Incident Commander: TBD  |  Escalation: #incident-api-outage",
         12, MED_GRAY, False)


# ── Save ─────────────────────────────────────────────────────────────────────
out_dir = "/private/var/folders/t6/_sx_03q50_v9w2jpnq683jmw0000gn/T/claude-run-x3rfnhgb"
out_path = os.path.join(out_dir, "API_Outage_PostIncident_Review.pptx")
prs.save(out_path)
print(f"Saved to: {out_path}")
