from __future__ import annotations

import json
from pathlib import Path

from pptx import Presentation
from pptx.dml.color import RGBColor
from pptx.enum.shapes import MSO_AUTO_SHAPE_TYPE
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.util import Inches, Pt


ROOT = Path(__file__).resolve().parents[1]
DOCS_DIR = ROOT / "docs"
DATA_FILE = DOCS_DIR / "presentaciones.json"
LOGO_LIGHT = ROOT / "styles" / "images" / "logo.png"
LOGO_DARK = ROOT / "styles" / "images" / "logob.png"
SLIDE_W = Inches(13.333)
SLIDE_H = Inches(7.5)


def rgb(hex_color: str) -> RGBColor:
    hex_color = hex_color.strip().lstrip("#")
    return RGBColor.from_string(hex_color)


def add_full_rect(slide, color: str) -> None:
    rect = slide.shapes.add_shape(
        MSO_AUTO_SHAPE_TYPE.RECTANGLE, 0, 0, SLIDE_W, SLIDE_H
    )
    rect.fill.solid()
    rect.fill.fore_color.rgb = rgb(color)
    rect.line.fill.background()


def add_band(slide, left, top, width, height, color: str) -> None:
    shape = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.RECTANGLE, left, top, width, height)
    shape.fill.solid()
    shape.fill.fore_color.rgb = rgb(color)
    shape.line.fill.background()


def add_logo(slide, dark: bool = False) -> None:
    path = LOGO_DARK if dark else LOGO_LIGHT
    if path.exists():
        slide.shapes.add_picture(str(path), Inches(11.55), Inches(0.35), height=Inches(0.55))


def set_text_style(paragraph, *, font_name: str, size: int, color: str, bold: bool = False) -> None:
    paragraph.font.name = font_name
    paragraph.font.size = Pt(size)
    paragraph.font.bold = bold
    paragraph.font.color.rgb = rgb(color)


def add_footer(slide, text: str, dark: bool = False) -> None:
    box = slide.shapes.add_textbox(Inches(0.6), Inches(7.0), Inches(8.7), Inches(0.25))
    tf = box.text_frame
    p = tf.paragraphs[0]
    p.text = text
    p.alignment = PP_ALIGN.LEFT
    set_text_style(p, font_name="Aptos", size=9, color="E5E7EB" if dark else "6B7280")


def add_title_slide(prs: Presentation, deck: dict, generated_at: str) -> None:
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    add_full_rect(slide, deck["secondary"])
    add_band(slide, Inches(0.55), Inches(0.55), Inches(0.22), Inches(5.9), deck["accent"])
    add_band(slide, Inches(9.9), Inches(0), Inches(3.43), Inches(7.5), deck["accent"])
    add_logo(slide, dark=True)

    eyebrow = slide.shapes.add_textbox(Inches(1.0), Inches(0.9), Inches(4.4), Inches(0.4))
    p = eyebrow.text_frame.paragraphs[0]
    p.text = deck["slides"][0].get("eyebrow", "")
    set_text_style(p, font_name="Bahnschrift", size=16, color="FDE68A", bold=True)

    title = slide.shapes.add_textbox(Inches(1.0), Inches(1.45), Inches(8.0), Inches(2.0))
    tf = title.text_frame
    tf.word_wrap = True
    p = tf.paragraphs[0]
    p.text = deck["slides"][0]["title"]
    set_text_style(p, font_name="Bahnschrift", size=28, color="F9FAFB", bold=True)

    subtitle = slide.shapes.add_textbox(Inches(1.0), Inches(3.45), Inches(7.6), Inches(1.3))
    tf = subtitle.text_frame
    tf.word_wrap = True
    p = tf.paragraphs[0]
    p.text = deck["slides"][0]["subtitle"]
    set_text_style(p, font_name="Aptos", size=16, color="E5E7EB")

    meta = slide.shapes.add_textbox(Inches(1.0), Inches(5.85), Inches(5.3), Inches(0.45))
    p = meta.text_frame.paragraphs[0]
    p.text = f"{deck['title']} | {generated_at}"
    set_text_style(p, font_name="Aptos", size=12, color="FDE68A")

    add_footer(slide, "Presentacion generada desde docs/presentaciones.json", dark=True)


def add_bullets_slide(prs: Presentation, deck: dict, slide_data: dict, generated_at: str, index: int, total: int) -> None:
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    add_full_rect(slide, "F8FAFC")
    add_band(slide, Inches(0), Inches(0), SLIDE_W, Inches(0.35), deck["secondary"])
    add_band(slide, Inches(0.6), Inches(0.72), Inches(0.2), Inches(0.5), deck["accent"])
    add_logo(slide, dark=False)

    title = slide.shapes.add_textbox(Inches(0.95), Inches(0.66), Inches(9.6), Inches(0.65))
    p = title.text_frame.paragraphs[0]
    p.text = slide_data["title"]
    set_text_style(p, font_name="Bahnschrift", size=24, color="0F172A", bold=True)

    highlight = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, Inches(0.95), Inches(1.45), Inches(11.2), Inches(0.78))
    highlight.fill.solid()
    highlight.fill.fore_color.rgb = rgb(deck["accent"])
    highlight.line.fill.background()
    tf = highlight.text_frame
    tf.margin_left = Pt(12)
    tf.margin_right = Pt(12)
    tf.vertical_anchor = MSO_ANCHOR.MIDDLE
    p = tf.paragraphs[0]
    p.text = slide_data.get("highlight", "")
    p.alignment = PP_ALIGN.LEFT
    set_text_style(p, font_name="Aptos", size=14, color="FFF7ED", bold=True)

    body = slide.shapes.add_textbox(Inches(1.05), Inches(2.55), Inches(10.3), Inches(3.8))
    tf = body.text_frame
    tf.word_wrap = True
    tf.margin_left = 0
    tf.margin_right = 0
    tf.clear()

    for i, bullet in enumerate(slide_data.get("bullets", [])):
        p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
        p.text = bullet
        p.level = 0
        p.space_after = Pt(10)
        set_text_style(p, font_name="Aptos", size=18, color="1F2937")

    badge = slide.shapes.add_shape(MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE, Inches(11.55), Inches(6.55), Inches(1.0), Inches(0.34))
    badge.fill.solid()
    badge.fill.fore_color.rgb = rgb(deck["secondary"])
    badge.line.fill.background()
    tf = badge.text_frame
    tf.vertical_anchor = MSO_ANCHOR.MIDDLE
    p = tf.paragraphs[0]
    p.text = f"{index}/{total}"
    p.alignment = PP_ALIGN.CENTER
    set_text_style(p, font_name="Bahnschrift", size=11, color="F8FAFC", bold=True)

    add_footer(slide, f"{deck['title']} | {generated_at}")


def build_deck(deck: dict, generated_at: str) -> Path:
    prs = Presentation()
    prs.slide_width = SLIDE_W
    prs.slide_height = SLIDE_H

    slides = deck["slides"]
    add_title_slide(prs, deck, generated_at)
    total = len(slides)
    for idx, slide_data in enumerate(slides[1:], start=2):
        add_bullets_slide(prs, deck, slide_data, generated_at, idx, total)

    output = ROOT / deck["output"]
    output.parent.mkdir(parents=True, exist_ok=True)
    prs.save(str(output))
    return output


def main() -> None:
    data = json.loads(DATA_FILE.read_text(encoding="utf-8"))
    generated_at = data.get("generated_at", "")
    outputs = []
    for deck in data.get("decks", []):
        outputs.append(build_deck(deck, generated_at))
    for output in outputs:
        print(output.relative_to(ROOT))


if __name__ == "__main__":
    main()
