"""
Unit tests for BarChartStrategy helper methods.
"""

from typing import Any
from unittest.mock import MagicMock

import plotly.graph_objects as go
import polars as pl
import pytest
from fields_metadata import FieldMetadata
from polychromos import HSLColor

from orama.color import (
    ColorAssignerByCategory,
    ColorRule,
    ColorSelectorStrategy,
)
from orama.strategies.bar import BarChartStrategy
from orama.variables import Aggregation


def _cat_meta() -> MagicMock:
    m = MagicMock(spec=FieldMetadata)
    m.categorical = True
    m.numeric = False
    m.derived = False
    m.effective_type = str
    m.extra = {}
    return m


def _make_bar(fields_metadata: dict[str, Any], **kwargs: Any) -> BarChartStrategy:
    return BarChartStrategy(
        fields_metadata=fields_metadata,
        category_variables=["cat"],
        aggregation=Aggregation(name="count", function="count"),
        **kwargs,
    )


@pytest.fixture
def cat_fields() -> dict[str, Any]:
    return {"cat": _cat_meta()}


@pytest.fixture
def bar(cat_fields: dict[str, Any]) -> BarChartStrategy:
    return _make_bar(cat_fields)


@pytest.fixture
def base_df() -> pl.DataFrame:
    return pl.DataFrame({"cat": ["A", "B", "C"], "count": [10, 20, 30]})


def test_prepare_df_returns_none_mean_by_default(
    bar: BarChartStrategy,
    base_df: pl.DataFrame,
    tr: Any,
) -> None:
    _, _, mean_value = bar._prepare_df(base_df, tr)
    assert mean_value is None


def test_prepare_df_count_mean_returns_float(
    cat_fields: dict[str, Any],
    tr: Any,
) -> None:
    instance = _make_bar(cat_fields, mean_category_name="Mean")
    df = pl.DataFrame({"cat": ["A", "B", "C"], "count": [10, 20, 30], "__total_count__": [10, 20, 30]})
    _, _, mean_value = instance._prepare_df(df, tr)
    assert isinstance(mean_value, float)


def test_prepare_df_alias_is_category_variable(
    bar: BarChartStrategy,
    base_df: pl.DataFrame,
    tr: Any,
) -> None:
    _, alias, _ = bar._prepare_df(base_df, tr)
    assert alias == "cat"


def test_compute_bar_colors_no_rules_returns_sequence(
    bar: BarChartStrategy,
    anchor_color: HSLColor,
    theme: Any,
) -> None:
    df = pl.DataFrame({"cat": ["A", "B", "C"], "count": [1, 2, 3]})
    result = bar._compute_bar_colors(df, "cat", theme)
    assert len(result) == df.height


def test_compute_bar_colors_with_rules_returns_sequence(
    cat_fields: dict[str, Any],
    anchor_colors: list[HSLColor],
    theme: Any,
) -> None:
    assigner = ColorAssignerByCategory(anchor_colors=anchor_colors)
    rule = ColorRule(assigner=assigner, selector=ColorSelectorStrategy())
    instance = _make_bar(cat_fields, color_rules=[rule])
    df = pl.DataFrame({"cat": ["A", "B", "C"], "count": [1, 2, 3]})
    result = instance._compute_bar_colors(df, "cat", theme)
    assert len(result) == df.height


def test_configure_bar_layout_showlegend_false(
    bar: BarChartStrategy,
    theme: Any,
) -> None:
    fig = go.Figure()
    bar._configure_bar_layout(fig, None, "Category", "Count", theme)
    assert fig.layout.showlegend is False


def test_configure_bar_layout_vertical_titles(
    bar: BarChartStrategy,
    theme: Any,
) -> None:
    fig = go.Figure()
    bar._configure_bar_layout(fig, None, "MyCategory", "MyValue", theme)
    assert fig.layout.xaxis.title.text == "MyCategory"
    assert fig.layout.yaxis.title.text == "MyValue"


def test_configure_bar_layout_horizontal_titles(
    cat_fields: dict[str, Any],
    theme: Any,
) -> None:
    instance = _make_bar(cat_fields, horizontal=True)
    fig = go.Figure()
    instance._configure_bar_layout(fig, None, "MyCategory", "MyValue", theme)
    assert fig.layout.xaxis.title.text == "MyValue"
    assert fig.layout.yaxis.title.text == "MyCategory"


def test_configure_bar_layout_no_hline_when_mean_none(
    bar: BarChartStrategy,
    theme: Any,
) -> None:
    fig = go.Figure()
    bar._configure_bar_layout(fig, None, "Category", "Count", theme)
    assert len(fig.layout.shapes) == 0


def test_configure_bar_layout_adds_hline_for_vertical_mean(
    cat_fields: dict[str, Any],
    theme: Any,
) -> None:
    instance = _make_bar(cat_fields, mean_annotation=True, mean_category_name="Mean")
    fig = go.Figure()
    instance._configure_bar_layout(fig, 5.0, "Category", "Count", theme)
    assert len(fig.layout.shapes) == 1
