"""Waterfall (bridge) chart renderer — shape-based bar chart."""

from __future__ import annotations

import math

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

from pptx_mcp.engine.diagrams._common import add_freeform_connector, add_textbox
from pptx_mcp.engine.layouts import _add_slide_title
from pptx_mcp.engine.shapes import parse_hex_color, set_corner_radius
from pptx_mcp.models.brand import BrandConfig
from pptx_mcp.models.slides import SlideDefinition


# Default bar colors when brand chart_colors are not available
_DEFAULT_INCREASE = "#28A745"
_DEFAULT_DECREASE = "#DC3545"
_DEFAULT_TOTAL = "#2D5F8A"


def _bar_color(bar_type: str, brand: BrandConfig) -> str:
    """Pick a color for a waterfall bar based on its type."""
    chart_colors = brand.colors.chart_colors
    if bar_type == "total":
        return chart_colors[0] if chart_colors else _DEFAULT_TOTAL
    elif bar_type == "increase":
        return brand.colors.success if brand.colors.success else _DEFAULT_INCREASE
    else:  # decrease
        return brand.colors.danger if brand.colors.danger else _DEFAULT_DECREASE


def render_waterfall_slide(
    slide: Slide,
    definition: SlideDefinition,
    brand: BrandConfig,
    slide_width: float,
) -> None:
    """Render a shape-based waterfall (bridge) chart.

    Each bar is a ROUNDED_RECTANGLE positioned at the correct running-total
    height. Thin connector lines bridge adjacent bar tops.
    """
    _add_slide_title(slide, definition.title, brand, slide_width)

    bars = definition.waterfall_bars or []
    if not bars:
        return

    n = len(bars)
    sp = brand.spacing
    content_w = slide_width - sp.margin_left - sp.margin_right
    chart_left = sp.margin_left + 0.6  # room for Y-axis values
    chart_top = sp.content_top + 0.3
    chart_w = content_w - 0.6
    chart_h = 4.5

    # --- compute running totals and value range -------------------------
    running = 0.0
    bar_bottoms: list[float] = []
    bar_tops: list[float] = []
    values: list[float] = []

    for bar in bars:
        if bar.bar_type == "total":
            bottom = 0.0
            top = bar.value
        else:
            bottom = running
            top = running + bar.value
        bar_bottoms.append(min(bottom, top))
        bar_tops.append(max(bottom, top))
        values.append(bar.value)
        if bar.bar_type != "total":
            running += bar.value
        else:
            running = bar.value

    all_vals = bar_bottoms + bar_tops
    val_min = min(all_vals)
    val_max = max(all_vals)
    val_range = val_max - val_min if val_max != val_min else 1.0

    # --- helper: value -> y coordinate in inches -----------------------
    def val_to_y(v: float) -> float:
        """Map a data value to a Y position (top of chart = max)."""
        return chart_top + chart_h * (1.0 - (v - val_min) / val_range)

    bar_w = min(chart_w / n * 0.65, 1.2)
    gap = (chart_w - bar_w * n) / max(n, 1)

    prev_top_y: float | None = None

    for i, bar in enumerate(bars):
        x = chart_left + i * (bar_w + gap) + gap / 2
        y_top = val_to_y(bar_tops[i])
        y_bot = val_to_y(bar_bottoms[i])
        bar_h = max(y_bot - y_top, 0.05)

        # --- bar rectangle ---
        color_hex = bar.color or _bar_color(bar.bar_type, brand)
        rect = slide.shapes.add_shape(
            MSO_SHAPE.ROUNDED_RECTANGLE,
            Inches(x), Inches(y_top),
            Inches(bar_w), Inches(bar_h),
        )
        rect.fill.solid()
        rect.fill.fore_color.rgb = parse_hex_color(color_hex)
        rect.line.fill.background()
        set_corner_radius(rect, brand.shape_style.card_corner_radius)

        # --- value label ---
        label_val = bar.value
        label_text = f"{label_val:+.0f}" if bar.bar_type != "total" else f"{label_val:.0f}"
        label_y = y_top - 0.3 if bar.bar_type != "decrease" else y_bot + 0.02
        add_textbox(
            slide, x, label_y, bar_w, 0.28,
            text=label_text,
            font_name=brand.fonts.body_font,
            font_size=10,
            bold=True,
            color=brand.colors.text_primary,
        )

        # --- x-axis label ---
        add_textbox(
            slide, x, chart_top + chart_h + 0.08, bar_w, 0.3,
            text=bar.label,
            font_name=brand.fonts.body_font,
            font_size=10,
            color=brand.colors.text_secondary,
        )

        # --- connector bridge from previous bar top ---
        if prev_top_y is not None and bar.bar_type != "total":
            cx1 = chart_left + (i - 1) * (bar_w + gap) + gap / 2 + bar_w
            cx2 = x
            conn_y = prev_top_y
            add_freeform_connector(
                slide, cx1, conn_y, cx2, conn_y,
                color=brand.colors.text_secondary,
                width=0.5,
            )

        prev_top_y = y_top
