"""Venn diagram renderer — 2 or 3 overlapping circles with labels."""

from __future__ import annotations

import math

from lxml import etree

from pptx.dml.color import RGBColor
from pptx.enum.shapes import MSO_SHAPE
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.slide import Slide
from pptx.util import Inches, Pt

from pptx_mcp.engine.diagrams._common import brand_color_at
from pptx_mcp.engine.layouts import _add_slide_title
from pptx_mcp.engine.shapes import parse_hex_color
from pptx_mcp.models.brand import BrandConfig
from pptx_mcp.models.slides import SlideDefinition


def _set_shape_opacity(shape: object, opacity_pct: int) -> None:
    """Set fill opacity on a shape (0-100)."""
    spPr = shape._element.spPr  # type: ignore[attr-defined]
    nsmap = {"a": "http://schemas.openxmlformats.org/drawingml/2006/main"}
    fills = spPr.findall("a:solidFill", nsmap)
    for fill_el in fills:
        clr_els = fill_el.findall("a:srgbClr", nsmap)
        for clr in clr_els:
            for alpha in clr.findall("a:alpha", nsmap):
                clr.remove(alpha)
            alpha_el = etree.SubElement(clr, f"{{{nsmap['a']}}}alpha")
            alpha_el.set("val", str(opacity_pct * 1000))


def render_venn_slide(
    slide: Slide,
    definition: SlideDefinition,
    brand: BrandConfig,
    slide_width: float,
) -> None:
    """Render a Venn diagram with 2 or 3 overlapping circles."""
    _add_slide_title(slide, definition.title, brand, slide_width)

    venn = definition.venn
    if venn is None:
        return

    circles = venn.circles
    n = len(circles)
    if n < 2:
        return

    sp = brand.spacing
    content_left = sp.margin_left
    content_top = sp.content_top + 0.2
    content_w = slide_width - sp.margin_left - sp.margin_right
    content_h = 7.5 - content_top - sp.margin_bottom

    # Circle size
    diameter = min(content_w * 0.38, content_h * 0.65)
    overlap_frac = 0.30  # 30% overlap

    cx = content_left + content_w / 2  # center of content area
    cy = content_top + content_h / 2

    if n == 2:
        # Two circles side by side with overlap
        offset = diameter * (1 - overlap_frac) / 2
        centers = [
            (cx - offset, cy),
            (cx + offset, cy),
        ]
    else:
        # Three circles in equilateral triangle arrangement
        radius_spread = diameter * (1 - overlap_frac) / 2
        angles = [270, 30, 150]  # top, bottom-right, bottom-left (degrees)
        centers = [
            (cx + radius_spread * math.cos(math.radians(a)),
             cy + radius_spread * math.sin(math.radians(a)))
            for a in angles
        ]

    # Draw circles
    for i, circle_data in enumerate(circles[:n]):
        fill_hex = circle_data.color or brand_color_at(brand, i)
        ccx, ccy = centers[i]

        oval = slide.shapes.add_shape(
            MSO_SHAPE.OVAL,
            Inches(ccx - diameter / 2), Inches(ccy - diameter / 2),
            Inches(diameter), Inches(diameter),
        )
        oval.fill.solid()
        oval.fill.fore_color.rgb = parse_hex_color(fill_hex)
        oval.line.fill.background()
        _set_shape_opacity(oval, 40)

        # Label centered in the non-overlapping portion
        if n == 2:
            # Push label away from center
            label_offset = diameter * 0.2
            lx = ccx + (-label_offset if i == 0 else label_offset)
            ly = ccy
        else:
            # Push label outward from the group center
            angle_rad = math.radians([270, 30, 150][i])
            label_offset = diameter * 0.15
            lx = ccx + label_offset * math.cos(angle_rad)
            ly = ccy + label_offset * math.sin(angle_rad)

        label_w = diameter * 0.55
        label_h = 0.8
        label_box = slide.shapes.add_textbox(
            Inches(lx - label_w / 2), Inches(ly - label_h / 2),
            Inches(label_w), Inches(label_h),
        )
        ltf = label_box.text_frame
        ltf.word_wrap = True
        ltf.vertical_anchor = MSO_ANCHOR.MIDDLE
        p = ltf.paragraphs[0]
        p.text = circle_data.label
        p.alignment = PP_ALIGN.CENTER
        run = p.runs[0]
        run.font.name = brand.fonts.heading_font
        run.font.size = Pt(12)
        run.font.bold = True
        run.font.color.rgb = parse_hex_color(brand.colors.text_primary)

        # Items under label
        for item_text in circle_data.items[:4]:
            ip = ltf.add_paragraph()
            ip.text = item_text
            ip.alignment = PP_ALIGN.CENTER
            irun = ip.runs[0]
            irun.font.name = brand.fonts.body_font
            irun.font.size = Pt(10)
            irun.font.color.rgb = parse_hex_color(brand.colors.text_secondary)

    # Intersection label
    if venn.intersection_label:
        int_w = 1.5
        int_h = 0.5
        int_box = slide.shapes.add_textbox(
            Inches(cx - int_w / 2), Inches(cy - int_h / 2),
            Inches(int_w), Inches(int_h),
        )
        itf = int_box.text_frame
        itf.word_wrap = True
        itf.vertical_anchor = MSO_ANCHOR.MIDDLE
        p = itf.paragraphs[0]
        p.text = venn.intersection_label
        p.alignment = PP_ALIGN.CENTER
        run = p.runs[0]
        run.font.name = brand.fonts.heading_font
        run.font.size = Pt(11)
        run.font.bold = True
        run.font.color.rgb = parse_hex_color(brand.colors.accent)
