"""
Tests for ScaleStrategy configuration.

Tests verify that scale strategies are properly defined, immutable,
and cover all required fields.
"""

import pytest

from shared.bbox import (
    ScaleStrategy,
    DEFAULT_STRATEGY,
    MANUAL_LABEL_STRATEGY,
    FIELD_SCALE_STRATEGIES,
)
from shared.fields import CLASS_NAMES


class TestScaleStrategyDataclass:
    """Tests for ScaleStrategy dataclass behavior."""

    def test_default_strategy_values(self):
        """Verify default strategy has expected default values."""
        strategy = ScaleStrategy()
        assert strategy.scale_x == 1.15
        assert strategy.scale_y == 1.15
        assert strategy.extra_top_ratio == 0.0
        assert strategy.extra_bottom_ratio == 0.0
        assert strategy.extra_left_ratio == 0.0
        assert strategy.extra_right_ratio == 0.0
        assert strategy.max_pad_x == 50
        assert strategy.max_pad_y == 50

    def test_scale_strategy_immutability(self):
        """Verify ScaleStrategy is frozen (immutable)."""
        strategy = ScaleStrategy()
        with pytest.raises(AttributeError):
            strategy.scale_x = 2.0  # type: ignore

    def test_custom_strategy_values(self):
        """Verify custom values are properly set."""
        strategy = ScaleStrategy(
            scale_x=1.5,
            scale_y=1.8,
            extra_top_ratio=0.6,
            extra_left_ratio=0.8,
            max_pad_x=100,
            max_pad_y=150,
        )
        assert strategy.scale_x == 1.5
        assert strategy.scale_y == 1.8
        assert strategy.extra_top_ratio == 0.6
        assert strategy.extra_left_ratio == 0.8
        assert strategy.max_pad_x == 100
        assert strategy.max_pad_y == 150


class TestDefaultStrategy:
    """Tests for DEFAULT_STRATEGY constant."""

    def test_default_strategy_is_scale_strategy(self):
        """Verify DEFAULT_STRATEGY is a ScaleStrategy instance."""
        assert isinstance(DEFAULT_STRATEGY, ScaleStrategy)

    def test_default_strategy_matches_default_values(self):
        """Verify DEFAULT_STRATEGY has same values as ScaleStrategy()."""
        expected = ScaleStrategy()
        assert DEFAULT_STRATEGY == expected


class TestManualLabelStrategy:
    """Tests for MANUAL_LABEL_STRATEGY constant."""

    def test_manual_label_strategy_is_scale_strategy(self):
        """Verify MANUAL_LABEL_STRATEGY is a ScaleStrategy instance."""
        assert isinstance(MANUAL_LABEL_STRATEGY, ScaleStrategy)

    def test_manual_label_strategy_has_no_scaling(self):
        """Verify MANUAL_LABEL_STRATEGY has scale factors of 1.0."""
        assert MANUAL_LABEL_STRATEGY.scale_x == 1.0
        assert MANUAL_LABEL_STRATEGY.scale_y == 1.0

    def test_manual_label_strategy_has_no_directional_expansion(self):
        """Verify MANUAL_LABEL_STRATEGY has no directional expansion."""
        assert MANUAL_LABEL_STRATEGY.extra_top_ratio == 0.0
        assert MANUAL_LABEL_STRATEGY.extra_bottom_ratio == 0.0
        assert MANUAL_LABEL_STRATEGY.extra_left_ratio == 0.0
        assert MANUAL_LABEL_STRATEGY.extra_right_ratio == 0.0

    def test_manual_label_strategy_has_small_max_pad(self):
        """Verify MANUAL_LABEL_STRATEGY has small max padding."""
        assert MANUAL_LABEL_STRATEGY.max_pad_x <= 15
        assert MANUAL_LABEL_STRATEGY.max_pad_y <= 15


class TestFieldScaleStrategies:
    """Tests for FIELD_SCALE_STRATEGIES dictionary."""

    def test_all_class_names_have_strategies(self):
        """Verify all field class names have defined strategies."""
        for class_name in CLASS_NAMES:
            assert class_name in FIELD_SCALE_STRATEGIES, (
                f"Missing strategy for field: {class_name}"
            )

    def test_strategies_are_scale_strategy_instances(self):
        """Verify all strategies are ScaleStrategy instances."""
        for field_name, strategy in FIELD_SCALE_STRATEGIES.items():
            assert isinstance(strategy, ScaleStrategy), (
                f"Strategy for {field_name} is not a ScaleStrategy"
            )

    def test_scale_values_are_greater_than_one(self):
        """Verify all scale values are >= 1.0 (expansion, not contraction)."""
        for field_name, strategy in FIELD_SCALE_STRATEGIES.items():
            assert strategy.scale_x >= 1.0, (
                f"{field_name} scale_x should be >= 1.0"
            )
            assert strategy.scale_y >= 1.0, (
                f"{field_name} scale_y should be >= 1.0"
            )

    def test_extra_ratios_are_non_negative(self):
        """Verify all extra ratios are >= 0."""
        for field_name, strategy in FIELD_SCALE_STRATEGIES.items():
            assert strategy.extra_top_ratio >= 0, (
                f"{field_name} extra_top_ratio should be >= 0"
            )
            assert strategy.extra_bottom_ratio >= 0, (
                f"{field_name} extra_bottom_ratio should be >= 0"
            )
            assert strategy.extra_left_ratio >= 0, (
                f"{field_name} extra_left_ratio should be >= 0"
            )
            assert strategy.extra_right_ratio >= 0, (
                f"{field_name} extra_right_ratio should be >= 0"
            )

    def test_max_pad_values_are_positive(self):
        """Verify all max_pad values are > 0."""
        for field_name, strategy in FIELD_SCALE_STRATEGIES.items():
            assert strategy.max_pad_x > 0, (
                f"{field_name} max_pad_x should be > 0"
            )
            assert strategy.max_pad_y > 0, (
                f"{field_name} max_pad_y should be > 0"
            )


class TestSpecificFieldStrategies:
    """Tests for specific field strategy configurations."""

    def test_ocr_number_expands_upward(self):
        """Verify ocr_number strategy expands upward to capture label."""
        strategy = FIELD_SCALE_STRATEGIES["ocr_number"]
        assert strategy.extra_top_ratio > 0.0
        assert strategy.extra_top_ratio >= 0.5  # Significant upward expansion

    def test_bankgiro_expands_leftward(self):
        """Verify bankgiro strategy expands leftward to capture prefix."""
        strategy = FIELD_SCALE_STRATEGIES["bankgiro"]
        assert strategy.extra_left_ratio > 0.0
        assert strategy.extra_left_ratio >= 0.5  # Significant leftward expansion

    def test_plusgiro_expands_leftward(self):
        """Verify plusgiro strategy expands leftward to capture prefix."""
        strategy = FIELD_SCALE_STRATEGIES["plusgiro"]
        assert strategy.extra_left_ratio > 0.0
        assert strategy.extra_left_ratio >= 0.5

    def test_amount_expands_rightward(self):
        """Verify amount strategy expands rightward for currency symbol."""
        strategy = FIELD_SCALE_STRATEGIES["amount"]
        assert strategy.extra_right_ratio > 0.0

    def test_invoice_date_expands_upward(self):
        """Verify invoice_date strategy expands upward to capture label."""
        strategy = FIELD_SCALE_STRATEGIES["invoice_date"]
        assert strategy.extra_top_ratio > 0.0

    def test_invoice_due_date_expands_upward_and_leftward(self):
        """Verify invoice_due_date strategy expands both up and left."""
        strategy = FIELD_SCALE_STRATEGIES["invoice_due_date"]
        assert strategy.extra_top_ratio > 0.0
        assert strategy.extra_left_ratio > 0.0

    def test_payment_line_has_minimal_expansion(self):
        """Verify payment_line has conservative expansion (machine code)."""
        strategy = FIELD_SCALE_STRATEGIES["payment_line"]
        # Payment line is machine-readable, needs minimal expansion
        assert strategy.scale_x <= 1.2
        assert strategy.scale_y <= 1.3
