"""Tests for chart formatting enhancements — axis, data labels, legend, style, smooth."""

from __future__ import annotations

import pytest
from pptx import Presentation
from pptx.util import Inches

from pptx_mcp.engine.charts import add_chart_to_slide
from pptx_mcp.models.slides import (
    AxisFormat,
    ChartData,
    ChartDataSeries,
    ChartElement,
    ChartType,
    DataLabelConfig,
    LegendConfig,
)


def _make_slide() -> tuple:
    """Create a presentation with one blank slide."""
    prs = Presentation()
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    return prs, slide


def _bar_element(**kwargs) -> ChartElement:
    """Create a basic bar chart element with optional overrides."""
    base = dict(
        type="chart",
        chart_type=ChartType.BAR,
        data=ChartData(
            categories=["Q1", "Q2", "Q3", "Q4"],
            series=[ChartDataSeries(name="Revenue", values=[100, 150, 130, 180])],
        ),
    )
    base.update(kwargs)
    return ChartElement(**base)


def _line_element(**kwargs) -> ChartElement:
    """Create a basic line chart element."""
    base = dict(
        type="chart",
        chart_type=ChartType.LINE,
        data=ChartData(
            categories=["Jan", "Feb", "Mar"],
            series=[ChartDataSeries(name="Trend", values=[10, 20, 15])],
        ),
    )
    base.update(kwargs)
    return ChartElement(**base)


# ---------------------------------------------------------------------------
# AxisFormat
# ---------------------------------------------------------------------------


class TestAxisFormat:
    def test_value_axis_min_max(self) -> None:
        prs, slide = _make_slide()
        elem = _bar_element(
            value_axis=AxisFormat(minimum=0, maximum=200, major_unit=50),
        )
        add_chart_to_slide(slide, elem)
        chart = slide.shapes[-1].chart
        assert chart.value_axis.minimum_scale == 0
        assert chart.value_axis.maximum_scale == 200

    def test_value_axis_number_format(self) -> None:
        prs, slide = _make_slide()
        elem = _bar_element(
            value_axis=AxisFormat(number_format="#,##0"),
        )
        add_chart_to_slide(slide, elem)
        chart = slide.shapes[-1].chart
        assert chart.value_axis.tick_labels.number_format == "#,##0"

    def test_value_axis_title(self) -> None:
        prs, slide = _make_slide()
        elem = _bar_element(
            value_axis=AxisFormat(title="Revenue ($)"),
        )
        add_chart_to_slide(slide, elem)
        chart = slide.shapes[-1].chart
        assert chart.value_axis.has_title is True

    def test_value_axis_gridlines(self) -> None:
        prs, slide = _make_slide()
        elem = _bar_element(
            value_axis=AxisFormat(has_gridlines=False),
        )
        add_chart_to_slide(slide, elem)
        chart = slide.shapes[-1].chart
        assert chart.value_axis.has_major_gridlines is False

    def test_category_axis_format(self) -> None:
        prs, slide = _make_slide()
        elem = _bar_element(
            category_axis=AxisFormat(title="Quarter"),
        )
        add_chart_to_slide(slide, elem)
        chart = slide.shapes[-1].chart
        assert chart.category_axis.has_title is True


# ---------------------------------------------------------------------------
# DataLabelConfig
# ---------------------------------------------------------------------------


class TestDataLabels:
    def test_show_value(self) -> None:
        prs, slide = _make_slide()
        elem = _bar_element(
            data_labels=DataLabelConfig(show_value=True),
        )
        add_chart_to_slide(slide, elem)
        chart = slide.shapes[-1].chart
        plot = chart.plots[0]
        assert plot.has_data_labels is True

    def test_show_percentage(self) -> None:
        prs, slide = _make_slide()
        elem = ChartElement(
            type="chart",
            chart_type=ChartType.PIE,
            data=ChartData(
                categories=["A", "B", "C"],
                series=[ChartDataSeries(name="Values", values=[30, 50, 20])],
            ),
            data_labels=DataLabelConfig(show_percentage=True),
        )
        add_chart_to_slide(slide, elem)
        chart = slide.shapes[-1].chart
        plot = chart.plots[0]
        assert plot.has_data_labels is True

    def test_data_label_position(self) -> None:
        prs, slide = _make_slide()
        elem = _bar_element(
            data_labels=DataLabelConfig(show_value=True, position="outside_end"),
        )
        add_chart_to_slide(slide, elem)
        # If no exception, position was applied

    def test_data_label_font_size(self) -> None:
        prs, slide = _make_slide()
        elem = _bar_element(
            data_labels=DataLabelConfig(show_value=True, font_size=8),
        )
        add_chart_to_slide(slide, elem)
        chart = slide.shapes[-1].chart
        plot = chart.plots[0]
        assert plot.data_labels.font.size is not None


# ---------------------------------------------------------------------------
# LegendConfig
# ---------------------------------------------------------------------------


class TestLegendConfig:
    def test_legend_position_right(self) -> None:
        prs, slide = _make_slide()
        elem = _bar_element(
            legend=LegendConfig(position="right"),
        )
        add_chart_to_slide(slide, elem)
        chart = slide.shapes[-1].chart
        assert chart.has_legend is True

    def test_legend_include_in_layout(self) -> None:
        prs, slide = _make_slide()
        elem = _bar_element(
            legend=LegendConfig(position="bottom", include_in_layout=True),
        )
        add_chart_to_slide(slide, elem)
        chart = slide.shapes[-1].chart
        assert chart.legend.include_in_layout is True

    def test_legend_position_top(self) -> None:
        prs, slide = _make_slide()
        elem = _bar_element(
            legend=LegendConfig(position="top"),
        )
        add_chart_to_slide(slide, elem)
        chart = slide.shapes[-1].chart
        assert chart.has_legend is True


# ---------------------------------------------------------------------------
# Chart style and smooth lines
# ---------------------------------------------------------------------------


class TestChartStyleAndSmooth:
    def test_chart_style_applied(self) -> None:
        prs, slide = _make_slide()
        elem = _bar_element(chart_style=2)
        add_chart_to_slide(slide, elem)
        chart = slide.shapes[-1].chart
        assert chart.style == 2

    def test_chart_style_range(self) -> None:
        """Chart style must be between 1 and 48."""
        with pytest.raises(Exception):
            _bar_element(chart_style=0)
        with pytest.raises(Exception):
            _bar_element(chart_style=49)

    def test_smooth_lines(self) -> None:
        prs, slide = _make_slide()
        elem = _line_element(smooth_lines=True)
        add_chart_to_slide(slide, elem)
        chart = slide.shapes[-1].chart
        for series in chart.series:
            assert series.smooth is True

    def test_no_smooth_by_default(self) -> None:
        prs, slide = _make_slide()
        elem = _line_element()
        add_chart_to_slide(slide, elem)
        chart = slide.shapes[-1].chart
        for series in chart.series:
            assert series.smooth is not True
