"""Tests for BrandEnforcementService: color utilities, font/color/logo enforcement."""
import uuid

import pytest

from models.pptx_models import (
    PptxAutoShapeBoxModel,
    PptxChartBoxModel,
    PptxFillModel,
    PptxFontModel,
    PptxParagraphModel,
    PptxPositionModel,
    PptxPresentationModel,
    PptxSlideModel,
    PptxTextBoxModel,
    PptxTextRunModel,
)
from models.sql.brand_config import BrandConfigModel
from pptx.enum.shapes import MSO_AUTO_SHAPE_TYPE
from services.brand_enforcement_service import (
    BrandEnforcementService,
    _contrast_ratio,
    _hex_to_rgb,
    _relative_luminance,
)


@pytest.fixture
def svc():
    return BrandEnforcementService()


@pytest.fixture
def brand() -> BrandConfigModel:
    return BrandConfigModel(
        client_id=uuid.uuid4(),
        primary_colors=["#FF0000", "#00FF00"],
        secondary_colors=["#0000FF"],
        fonts={"heading": "Montserrat", "body": "Open Sans"},
        logo_paths=["/logos/acme.png"],
    )


class TestColorUtilities:
    def test_hex_to_rgb_six_chars(self):
        assert _hex_to_rgb("FF0000") == (255, 0, 0)
        assert _hex_to_rgb("00FF00") == (0, 255, 0)

    def test_hex_to_rgb_with_hash(self):
        assert _hex_to_rgb("#0000FF") == (0, 0, 255)

    def test_hex_to_rgb_three_chars(self):
        assert _hex_to_rgb("F00") == (255, 0, 0)

    def test_white_has_high_luminance(self):
        assert _relative_luminance("FFFFFF") > 0.9

    def test_black_has_low_luminance(self):
        assert _relative_luminance("000000") < 0.01

    def test_contrast_ratio_black_vs_white(self):
        white_lum = _relative_luminance("FFFFFF")
        black_lum = _relative_luminance("000000")
        ratio = _contrast_ratio(white_lum, black_lum)
        assert ratio > 20  # Should be ~21:1


class TestBrandColors:
    def test_get_brand_colors_list(self, svc, brand):
        colors = svc.get_brand_colors_list(brand)
        assert "FF0000" in colors
        assert "00FF00" in colors
        assert "0000FF" in colors

    def test_fallback_when_no_colors(self, svc):
        brand = BrandConfigModel(
            client_id=uuid.uuid4(),
            primary_colors=None,
            secondary_colors=None,
        )
        colors = svc.get_brand_colors_list(brand)
        assert len(colors) > 0  # Defaults
        assert "4472C4" in colors


class TestEnforceOnPptxModel:
    def _make_text_slide(self, font_name="Arial", font_size=14):
        return PptxSlideModel(shapes=[
            PptxTextBoxModel(
                position=PptxPositionModel(left=10, top=10, width=200, height=50),
                paragraphs=[
                    PptxParagraphModel(
                        text="Hello World",
                        font=PptxFontModel(name=font_name, size=font_size, color="000000"),
                    )
                ],
            )
        ])

    def test_fonts_replaced_with_brand_fonts(self, svc, brand):
        model = PptxPresentationModel(slides=[
            self._make_text_slide("Arial", 32),  # Title slide (idx=0) → heading font
            self._make_text_slide("Times", 14),   # Content slide → body font
        ])
        result = svc.enforce_on_pptx_model(model, brand)
        # Slide 0 (title): heading font
        assert result.slides[0].shapes[0].paragraphs[0].font.name == "Montserrat"
        # Slide 1 (content): body font
        assert result.slides[1].shapes[0].paragraphs[0].font.name == "Open Sans"

    def test_logo_added_to_content_slides_only(self, svc, brand):
        model = PptxPresentationModel(slides=[
            self._make_text_slide(),  # Title slide — no logo
            self._make_text_slide(),  # Content slide — should get logo
            self._make_text_slide(),  # Another content slide
        ])
        result = svc.enforce_on_pptx_model(model, brand)

        # Slide 0: no logo shape added (still 1 shape)
        assert len(result.slides[0].shapes) == 1
        # Slides 1-2: logo added (2 shapes each)
        assert len(result.slides[1].shapes) == 2
        assert len(result.slides[2].shapes) == 2

    def test_no_logo_when_no_logo_paths(self, svc):
        brand_no_logo = BrandConfigModel(
            client_id=uuid.uuid4(),
            fonts={"heading": "Inter", "body": "Inter"},
            logo_paths=None,
        )
        model = PptxPresentationModel(slides=[
            self._make_text_slide(),
            self._make_text_slide(),
        ])
        result = svc.enforce_on_pptx_model(model, brand_no_logo)
        assert len(result.slides[1].shapes) == 1

    def test_chart_gets_brand_colors(self, svc, brand):
        chart = PptxChartBoxModel(
            position=PptxPositionModel(left=0, top=0, width=400, height=300),
            chart_type="bar",
            chart_data={"categories": ["A"], "series": [{"name": "S", "values": [1]}]},
        )
        model = PptxPresentationModel(slides=[
            PptxSlideModel(shapes=[chart]),
        ])
        result = svc.enforce_on_pptx_model(model, brand)
        assert result.slides[0].shapes[0].brand_colors is not None
        assert "FF0000" in result.slides[0].shapes[0].brand_colors

    def test_contrast_fix_white_on_white(self, svc, brand):
        """White text on white bg should be auto-corrected to black."""
        slide = PptxSlideModel(shapes=[
            PptxTextBoxModel(
                position=PptxPositionModel(left=0, top=0, width=100, height=50),
                paragraphs=[
                    PptxParagraphModel(
                        text="Invisible",
                        font=PptxFontModel(name="Arial", size=14, color="FFFFFF"),
                    )
                ],
            )
        ])
        # Default bg is white (FFFFFF)
        model = PptxPresentationModel(slides=[slide])
        result = svc.enforce_on_pptx_model(model, brand)
        # After contrast fix, text should be dark
        assert result.slides[0].shapes[0].paragraphs[0].font.color == "000000"
