from pathlib import Path
import textwrap

from PIL import Image, ImageDraw, ImageFont
from pptx import Presentation
from pptx.dml.color import RGBColor
from pptx.enum.shapes import MSO_AUTO_SHAPE_TYPE, MSO_CONNECTOR
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.util import Inches, Pt


ROOT = Path(__file__).resolve().parent
OUT = ROOT / "infografia_clase_api_big_data"
OUT.mkdir(exist_ok=True)

PPTX_PATH = OUT / "infografia_clase_api_big_data.pptx"
PNG_PATH = OUT / "infografia_clase_api_big_data.png"
LOGO = ROOT / "ucentral_logo_block.png"

W, H = 16, 9

COLORS = {
    "ink": RGBColor(26, 32, 44),
    "muted": RGBColor(84, 96, 112),
    "paper": RGBColor(248, 250, 252),
    "white": RGBColor(255, 255, 255),
    "teal": RGBColor(19, 136, 128),
    "blue": RGBColor(35, 94, 170),
    "orange": RGBColor(226, 128, 48),
    "red": RGBColor(184, 58, 75),
    "green": RGBColor(76, 143, 88),
    "line": RGBColor(213, 221, 230),
}


def rgb_hex(c):
    return f"#{c[0]:02x}{c[1]:02x}{c[2]:02x}"


def add_shape(slide, shape_type, x, y, w, h, fill, line=None, radius=False):
    shp = slide.shapes.add_shape(shape_type, Inches(x), Inches(y), Inches(w), Inches(h))
    shp.fill.solid()
    shp.fill.fore_color.rgb = fill
    if line is None:
        shp.line.fill.background()
    else:
        shp.line.color.rgb = line
        shp.line.width = Pt(1)
    return shp


def add_text(slide, text, x, y, w, h, size=16, color=None, bold=False, align="left"):
    box = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
    tf = box.text_frame
    tf.clear()
    tf.margin_left = Pt(6)
    tf.margin_right = Pt(6)
    tf.margin_top = Pt(2)
    tf.margin_bottom = Pt(2)
    tf.word_wrap = True
    tf.vertical_anchor = MSO_ANCHOR.TOP
    p = tf.paragraphs[0]
    p.text = text
    p.font.name = "Aptos"
    p.font.size = Pt(size)
    p.font.bold = bold
    p.font.color.rgb = color or COLORS["ink"]
    p.alignment = {"left": PP_ALIGN.LEFT, "center": PP_ALIGN.CENTER, "right": PP_ALIGN.RIGHT}[align]
    return box


def add_multiline(slide, lines, x, y, w, h, size=12, color=None, bullet=False):
    box = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
    tf = box.text_frame
    tf.clear()
    tf.margin_left = Pt(8)
    tf.margin_right = Pt(8)
    tf.margin_top = Pt(5)
    tf.margin_bottom = Pt(5)
    tf.word_wrap = True
    for i, line in enumerate(lines):
        p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
        p.text = line
        p.font.name = "Aptos"
        p.font.size = Pt(size)
        p.font.color.rgb = color or COLORS["ink"]
        if bullet:
            p.level = 0
            p._p.get_or_add_pPr().set("marL", "160000")
    return box


def build_pptx():
    prs = Presentation()
    prs.slide_width = Inches(W)
    prs.slide_height = Inches(H)
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    slide.background.fill.solid()
    slide.background.fill.fore_color.rgb = COLORS["paper"]

    # Header band
    add_shape(slide, MSO_AUTO_SHAPE_TYPE.RECTANGLE, 0, 0, 16, 1.15, RGBColor(235, 244, 242))
    add_shape(slide, MSO_AUTO_SHAPE_TYPE.RECTANGLE, 0, 1.08, 16, 0.05, COLORS["teal"])
    if LOGO.exists():
        slide.shapes.add_picture(str(LOGO), Inches(13.48), Inches(0.16), height=Inches(0.78))
    add_text(slide, "De la API al insight", 0.55, 0.17, 7.2, 0.45, 25, COLORS["ink"], True)
    add_text(
        slide,
        "Infografía de clase: análisis colaborativo de APIs públicas con Python para proyectos Big Data",
        0.56,
        0.62,
        10.6,
        0.32,
        10.5,
        COLORS["muted"],
    )
    add_text(slide, "90 min", 11.6, 0.35, 1.15, 0.34, 15, COLORS["teal"], True, "center")

    # Left context panel
    add_shape(slide, MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, 0.55, 1.45, 3.25, 6.75, COLORS["white"], COLORS["line"])
    add_text(slide, "Punto de partida", 0.78, 1.67, 2.7, 0.35, 15, COLORS["blue"], True)
    add_multiline(
        slide,
        [
            "Asignatura: Big Data",
            "Estudiantes: Ingeniería en Informática, Plan de Continuidad.",
            "Necesidad: participación asincrónica desigual en el AVA.",
            "Respuesta didáctica: ruta activa, colaborativa, trazable y evaluable.",
        ],
        0.74,
        2.1,
        2.85,
        1.7,
        11,
        COLORS["ink"],
    )
    add_text(slide, "Resultado de aprendizaje", 0.78, 4.05, 2.75, 0.28, 13, COLORS["teal"], True)
    add_multiline(
        slide,
        [
            "Analizar una API pública como fuente de datos para Big Data, conectarse con Python, interpretar la información obtenida y justificar su pertinencia técnica en el AVA.",
        ],
        0.74,
        4.38,
        2.85,
        1.15,
        11,
        COLORS["ink"],
    )
    add_text(slide, "Interacciones clave", 0.78, 5.76, 2.75, 0.25, 13, COLORS["orange"], True)
    add_multiline(
        slide,
        ["Estudiante-contenido", "Estudiante-estudiante", "Estudiante-docente"],
        0.92,
        6.12,
        2.55,
        0.8,
        11,
        COLORS["ink"],
    )
    add_text(slide, "Mediación: Moodle + herramientas web", 0.77, 7.26, 2.85, 0.38, 10.5, COLORS["muted"])

    # Timeline center
    add_text(slide, "Secuencia de la clase", 4.15, 1.42, 5.8, 0.35, 16, COLORS["ink"], True)
    x0, y0 = 4.05, 2.05
    steps = [
        ("1", "Inicio", "10 min", "Propósito y consigna en Moodle", COLORS["blue"]),
        ("2", "Diagnóstico", "10 min", "Forms: APIs, Python, JSON y Big Data", COLORS["teal"]),
        ("3", "Teoría activa", "15 min", "H5P: API, endpoint, HTTP, JSON", COLORS["orange"]),
        ("4", "Demo Python", "15 min", "Colab/Jupyter: request, status, JSON, DataFrame", COLORS["red"]),
        ("5", "Trabajo grupal", "20 min", "Analisis de API y notebook colaborativo", COLORS["green"]),
        ("6", "Socializacion", "8 min", "Padlet/Miro/Mentimeter: hallazgos y limites", COLORS["blue"]),
        ("7", "Salida", "7 min", "Cuestionario Moodle con retroalimentacion", COLORS["teal"]),
        ("8", "Cierre", "5 min", "Foro y reflexión individual", COLORS["orange"]),
    ]
    for idx, (num, title, mins, desc, color) in enumerate(steps):
        col = idx % 2
        row = idx // 2
        x = x0 + col * 3.35
        y = y0 + row * 1.23
        add_shape(slide, MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, x, y, 3.05, 0.9, COLORS["white"], COLORS["line"])
        add_shape(slide, MSO_AUTO_SHAPE_TYPE.OVAL, x + 0.16, y + 0.19, 0.48, 0.48, color)
        add_text(slide, num, x + 0.17, y + 0.26, 0.45, 0.2, 10, COLORS["white"], True, "center")
        add_text(slide, f"{title} · {mins}", x + 0.72, y + 0.14, 2.2, 0.22, 11.5, COLORS["ink"], True)
        add_text(slide, desc, x + 0.72, y + 0.43, 2.15, 0.34, 8.8, COLORS["muted"])

    # Connectors
    for row in range(4):
        y = y0 + row * 1.23 + 0.45
        c = slide.shapes.add_connector(MSO_CONNECTOR.STRAIGHT, Inches(7.1), Inches(y), Inches(7.38), Inches(y))
        c.line.color.rgb = COLORS["line"]
        c.line.width = Pt(1.5)
    for row in range(3):
        c = slide.shapes.add_connector(MSO_CONNECTOR.STRAIGHT, Inches(5.6), Inches(y0 + row * 1.23 + 0.92), Inches(5.6), Inches(y0 + (row + 1) * 1.23))
        c.line.color.rgb = COLORS["line"]
        c.line.width = Pt(1.5)
        c = slide.shapes.add_connector(MSO_CONNECTOR.STRAIGHT, Inches(8.95), Inches(y0 + row * 1.23 + 0.92), Inches(8.95), Inches(y0 + (row + 1) * 1.23))
        c.line.color.rgb = COLORS["line"]
        c.line.width = Pt(1.5)

    # Right tools and evaluation panels
    add_shape(slide, MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, 10.45, 1.45, 4.95, 2.75, COLORS["white"], COLORS["line"])
    add_text(slide, "Herramientas web", 10.72, 1.66, 3.8, 0.32, 15, COLORS["blue"], True)
    chips = [
        ("Moodle", COLORS["blue"]),
        ("Forms", COLORS["teal"]),
        ("H5P", COLORS["orange"]),
        ("Colab/Jupyter", COLORS["red"]),
        ("Padlet/Miro", COLORS["green"]),
        ("Foro", COLORS["blue"]),
        ("Cuestionario", COLORS["teal"]),
    ]
    cx, cy = 10.72, 2.14
    for label, color in chips:
        width = 0.56 + len(label) * 0.075
        if cx + width > 15.1:
            cx = 10.72
            cy += 0.52
        add_shape(slide, MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, cx, cy, width, 0.34, RGBColor(244, 247, 250), color)
        add_text(slide, label, cx + 0.05, cy + 0.07, width - 0.1, 0.15, 8.2, COLORS["ink"], True, "center")
        cx += width + 0.18
    add_text(slide, "Función pedagógica", 10.72, 3.45, 2.4, 0.25, 11.5, COLORS["teal"], True)
    add_text(slide, "organizar · activar · ejecutar · colaborar · evaluar · retroalimentar", 10.72, 3.74, 4.35, 0.24, 9.2, COLORS["muted"])

    add_shape(slide, MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, 10.45, 4.48, 4.95, 2.15, COLORS["white"], COLORS["line"])
    add_text(slide, "Evidencias y evaluación", 10.72, 4.69, 3.8, 0.32, 15, COLORS["teal"], True)
    add_multiline(
        slide,
        [
            "Diagnóstico inicial vs cuestionario de salida.",
            "Notebook grupal: conexión, JSON, DataFrame, interpretación y límites.",
            "Foro: síntesis de API + comentario técnico a otro equipo.",
            "Mural colaborativo y reflexión individual.",
        ],
        10.67,
        5.09,
        4.48,
        1.18,
        9.5,
        COLORS["ink"],
    )

    add_shape(slide, MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, 10.45, 6.91, 4.95, 1.29, COLORS["white"], COLORS["line"])
    add_text(slide, "Metas observables", 10.72, 7.08, 3.8, 0.26, 13, COLORS["orange"], True)
    metrics = [("+20%", "mejora grupal"), ("2", "intervenciones por equipo"), ("80%", "finalización AVA")]
    for i, (value, label) in enumerate(metrics):
        x = 10.78 + i * 1.48
        add_text(slide, value, x, 7.42, 1.1, 0.26, 15, [COLORS["teal"], COLORS["blue"], COLORS["green"]][i], True, "center")
        add_text(slide, label, x - 0.05, 7.73, 1.2, 0.25, 7.8, COLORS["muted"], False, "center")

    # Footer
    add_shape(slide, MSO_AUTO_SHAPE_TYPE.RECTANGLE, 0, 8.55, 16, 0.45, RGBColor(238, 242, 247))
    add_text(
        slide,
        "Fundamento: AVA como espacio activo de interacción y evidencia | Biggs & Tang · Moore · García Aretio · Nicol & Macfarlane-Dick",
        0.55,
        8.66,
        14.8,
        0.18,
        8.5,
        COLORS["muted"],
        False,
        "center",
    )

    prs.save(PPTX_PATH)


def draw_wrapped(draw, text, xy, font, fill, width, line_spacing=4, anchor=None):
    words = text.split()
    lines = []
    cur = ""
    for word in words:
        trial = (cur + " " + word).strip()
        if draw.textbbox((0, 0), trial, font=font)[2] <= width:
            cur = trial
        else:
            if cur:
                lines.append(cur)
            cur = word
    if cur:
        lines.append(cur)
    x, y = xy
    for line in lines:
        draw.text((x, y), line, font=font, fill=fill, anchor=anchor)
        y += font.size + line_spacing
    return y


def build_png():
    scale = 2
    img = Image.new("RGB", (1600 * scale, 900 * scale), "#f8fafc")
    d = ImageDraw.Draw(img)

    def f(size, bold=False):
        candidates = [
            "/System/Library/Fonts/Supplemental/Arial Bold.ttf" if bold else "/System/Library/Fonts/Supplemental/Arial.ttf",
            "/Library/Fonts/Arial Bold.ttf" if bold else "/Library/Fonts/Arial.ttf",
            "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" if bold else "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
        ]
        for p in candidates:
            if Path(p).exists():
                return ImageFont.truetype(p, size * scale)
        return ImageFont.load_default()

    def S(v):
        return int(v * scale)

    ink = "#1a202c"
    muted = "#546070"
    teal = "#138880"
    blue = "#235eaa"
    orange = "#e28030"
    red = "#b83a4b"
    green = "#4c8f58"
    line = "#d5dde6"
    white = "#ffffff"

    d.rectangle([0, 0, S(1600), S(115)], fill="#ebf4f2")
    d.rectangle([0, S(108), S(1600), S(113)], fill=teal)
    d.text((S(56), S(18)), "De la API al insight", font=f(32, True), fill=ink)
    d.text((S(58), S(65)), "Infografía de clase: análisis colaborativo de APIs públicas con Python para proyectos Big Data", font=f(16), fill=muted)
    d.rounded_rectangle([S(1160), S(35), S(1280), S(72)], radius=S(12), fill="#ffffff", outline=teal, width=S(2))
    d.text((S(1220), S(42)), "90 min", font=f(18, True), fill=teal, anchor="ma")
    if LOGO.exists():
        logo = Image.open(LOGO).convert("RGBA")
        logo.thumbnail((S(210), S(80)))
        img.paste(logo, (S(1350), S(17)), logo)

    # Panels
    d.rounded_rectangle([S(55), S(145), S(380), S(820)], radius=S(14), fill=white, outline=line, width=S(2))
    d.text((S(78), S(168)), "Punto de partida", font=f(19, True), fill=blue)
    y = S(212)
    for t in [
        "Asignatura: Big Data",
        "Estudiantes: Ingeniería en Informática, Plan de Continuidad.",
        "Necesidad: participación asincrónica desigual en el AVA.",
        "Respuesta didáctica: ruta activa, colaborativa, trazable y evaluable.",
    ]:
        y = draw_wrapped(d, t, (S(78), y), f(14), ink, S(280), S(4)) + S(8)
    d.text((S(78), S(405)), "Resultado de aprendizaje", font=f(16, True), fill=teal)
    draw_wrapped(
        d,
        "Analizar una API pública como fuente de datos para Big Data, conectarse con Python, interpretar la información obtenida y justificar su pertinencia técnica en el AVA.",
        (S(78), S(438)),
        f(14),
        ink,
        S(280),
        S(4),
    )
    d.text((S(78), S(576)), "Interacciones clave", font=f(16, True), fill=orange)
    for i, t in enumerate(["Estudiante-contenido", "Estudiante-estudiante", "Estudiante-docente"]):
        d.text((S(96), S(616 + i * 30)), t, font=f(14), fill=ink)
    d.text((S(78), S(728)), "Mediación: Moodle + herramientas web", font=f(13), fill=muted)

    d.text((S(415), S(142)), "Secuencia de la clase", font=f(21, True), fill=ink)
    steps = [
        ("1", "Inicio", "10 min", "Propósito y consigna en Moodle", blue),
        ("2", "Diagnóstico", "10 min", "Forms: APIs, Python, JSON y Big Data", teal),
        ("3", "Teoría activa", "15 min", "H5P: API, endpoint, HTTP, JSON", orange),
        ("4", "Demo Python", "15 min", "Colab/Jupyter: request, status, JSON, DataFrame", red),
        ("5", "Trabajo grupal", "20 min", "Analisis de API y notebook colaborativo", green),
        ("6", "Socializacion", "8 min", "Padlet/Miro/Mentimeter: hallazgos y limites", blue),
        ("7", "Salida", "7 min", "Cuestionario Moodle con retroalimentacion", teal),
        ("8", "Cierre", "5 min", "Foro y reflexión individual", orange),
    ]
    for idx, (num, title, mins, desc, color) in enumerate(steps):
        col = idx % 2
        row = idx // 2
        x = S(405 + col * 335)
        y = S(205 + row * 123)
        d.rounded_rectangle([x, y, x + S(305), y + S(90)], radius=S(14), fill=white, outline=line, width=S(2))
        d.ellipse([x + S(16), y + S(19), x + S(64), y + S(67)], fill=color)
        d.text((x + S(40), y + S(31)), num, font=f(14, True), fill=white, anchor="ma")
        d.text((x + S(72), y + S(15)), f"{title} · {mins}", font=f(14, True), fill=ink)
        draw_wrapped(d, desc, (x + S(72), y + S(45)), f(11), muted, S(215), S(2))

    d.rounded_rectangle([S(1045), S(145), S(1540), S(420)], radius=S(14), fill=white, outline=line, width=S(2))
    d.text((S(1072), S(166)), "Herramientas web", font=f(19, True), fill=blue)
    chips = [("Moodle", blue), ("Forms", teal), ("H5P", orange), ("Colab/Jupyter", red), ("Padlet/Miro", green), ("Foro", blue), ("Cuestionario", teal)]
    cx, cy = S(1072), S(214)
    for label, color in chips:
        tw = d.textbbox((0, 0), label, font=f(11, True))[2]
        ww = tw + S(30)
        if cx + ww > S(1510):
            cx = S(1072)
            cy += S(52)
        d.rounded_rectangle([cx, cy, cx + ww, cy + S(34)], radius=S(10), fill="#f4f7fa", outline=color, width=S(2))
        d.text((cx + ww / 2, cy + S(8)), label, font=f(11, True), fill=ink, anchor="ma")
        cx += ww + S(18)
    d.text((S(1072), S(345)), "Función pedagógica", font=f(14, True), fill=teal)
    draw_wrapped(d, "organizar · activar · ejecutar · colaborar · evaluar · retroalimentar", (S(1072), S(374)), f(12), muted, S(430), S(2))

    d.rounded_rectangle([S(1045), S(448), S(1540), S(663)], radius=S(14), fill=white, outline=line, width=S(2))
    d.text((S(1072), S(469)), "Evidencias y evaluación", font=f(19, True), fill=teal)
    y = S(510)
    for t in [
        "Diagnóstico inicial vs cuestionario de salida.",
        "Notebook grupal: conexión, JSON, DataFrame, interpretación y límites.",
        "Foro: síntesis de API + comentario técnico a otro equipo.",
        "Mural colaborativo y reflexión individual.",
    ]:
        y = draw_wrapped(d, t, (S(1072), y), f(12), ink, S(420), S(3)) + S(3)

    d.rounded_rectangle([S(1045), S(691), S(1540), S(820)], radius=S(14), fill=white, outline=line, width=S(2))
    d.text((S(1072), S(708)), "Metas observables", font=f(16, True), fill=orange)
    for i, (value, label, color) in enumerate([("+20%", "mejora grupal", teal), ("2", "intervenciones por equipo", blue), ("80%", "finalización AVA", green)]):
        x = S(1120 + i * 148)
        d.text((x, S(742)), value, font=f(24, True), fill=color, anchor="ma")
        draw_wrapped(d, label, (x - S(58), S(774)), f(10), muted, S(116), S(1))

    d.rectangle([0, S(855), S(1600), S(900)], fill="#eef2f7")
    d.text((S(800), S(868)), "Fundamento: AVA como espacio activo de interacción y evidencia | Biggs & Tang · Moore · García Aretio · Nicol & Macfarlane-Dick", font=f(11), fill=muted, anchor="ma")

    img = img.resize((1600, 900), Image.Resampling.LANCZOS)
    img.save(PNG_PATH)


if __name__ == "__main__":
    build_pptx()
    build_png()
    print(PPTX_PATH)
    print(PNG_PATH)
