"""Tests for shape utilities including color contrast functions and shape type expansion."""

from __future__ import annotations

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

from pptx_mcp.engine.shapes import (
    SHAPE_TYPE_MAP,
    add_shape_to_slide,
    contrast_ratio,
    ensure_readable_text_color,
    relative_luminance,
)
from pptx_mcp.models.slides import Position, ShapeElement, ShapeType


class TestRelativeLuminance:
    def test_black_is_zero(self) -> None:
        assert relative_luminance("#000000") == pytest.approx(0.0, abs=1e-6)

    def test_white_is_one(self) -> None:
        assert relative_luminance("#FFFFFF") == pytest.approx(1.0, abs=1e-6)

    def test_mid_gray(self) -> None:
        lum = relative_luminance("#808080")
        assert 0.2 < lum < 0.25  # sRGB mid-gray ≈ 0.216


class TestContrastRatio:
    def test_black_white(self) -> None:
        ratio = contrast_ratio("#000000", "#FFFFFF")
        assert ratio == pytest.approx(21.0, abs=0.1)

    def test_same_color(self) -> None:
        ratio = contrast_ratio("#336699", "#336699")
        assert ratio == pytest.approx(1.0, abs=0.01)

    def test_symmetry(self) -> None:
        r1 = contrast_ratio("#1A1A1A", "#E0E0E0")
        r2 = contrast_ratio("#E0E0E0", "#1A1A1A")
        assert r1 == pytest.approx(r2, abs=0.01)


class TestEnsureReadableTextColor:
    def test_sufficient_contrast_returns_preferred(self) -> None:
        # Dark blue text on white background — good contrast
        result = ensure_readable_text_color("#FFFFFF", "#1B2A4A")
        assert result == "#1B2A4A"

    def test_insufficient_contrast_returns_dark_fallback(self) -> None:
        # Light yellow text on white background — bad contrast
        result = ensure_readable_text_color("#FFFFFF", "#FFFF99")
        assert result == "#1A1A1A"

    def test_dark_bg_returns_light_fallback(self) -> None:
        # Dark text on dark background — should flip to white
        result = ensure_readable_text_color("#1A1A1A", "#333333")
        assert result == "#FFFFFF"

    def test_custom_fallbacks(self) -> None:
        result = ensure_readable_text_color(
            "#FFFFFF", "#FFFFCC",
            fallback_dark="#000000", fallback_light="#FFFFFF",
        )
        assert result == "#000000"

    def test_custom_min_ratio(self) -> None:
        # Lower threshold allows weaker contrast
        result = ensure_readable_text_color(
            "#FFFFFF", "#888888", min_ratio=2.0,
        )
        # Gray on white has ~4.0 contrast which passes 2.0 threshold
        assert result == "#888888"


# ---------------------------------------------------------------------------
# Shape type expansion (v0.8.0)
# ---------------------------------------------------------------------------


class TestNewShapeTypes:
    """Verify new shape types render without errors."""

    @pytest.mark.parametrize("shape_type", [
        ShapeType.OCTAGON,
        ShapeType.STAR_5,
        ShapeType.STAR_6,
        ShapeType.HEART,
        ShapeType.LIGHTNING,
        ShapeType.CLOUD,
        ShapeType.BLOCK_ARC,
        ShapeType.CROSS,
        ShapeType.DONUT,
        ShapeType.NO_SYMBOL,
    ])
    def test_new_shape_renders(self, shape_type: ShapeType) -> None:
        prs = Presentation()
        slide = prs.slides.add_slide(prs.slide_layouts[6])
        elem = ShapeElement(
            type="shape",
            shape_type=shape_type,
            position=Position(left=1.0, top=1.0, width=2.0, height=2.0),
            fill_color="#3366CC",
        )
        add_shape_to_slide(slide, elem, 0)
        assert len(list(slide.shapes)) == 1

    def test_all_new_types_in_map(self) -> None:
        new_types = [
            ShapeType.OCTAGON, ShapeType.STAR_5, ShapeType.STAR_6,
            ShapeType.HEART, ShapeType.LIGHTNING, ShapeType.CLOUD,
            ShapeType.BLOCK_ARC, ShapeType.CROSS, ShapeType.DONUT,
            ShapeType.NO_SYMBOL,
        ]
        for st in new_types:
            assert st in SHAPE_TYPE_MAP, f"{st} missing from SHAPE_TYPE_MAP"
