"""Tests for currency pattern matching."""
import pytest

from app.patterns.currency_patterns import CurrencyPatternMatcher, currency_matcher


class TestCurrencyPatternMatcher:
    """Test currency and amount extraction."""

    def test_total_explicit(self) -> None:
        """Test 'TOTAL $XX.XX' pattern."""
        text = "TOTAL $45.67"
        result = currency_matcher.extract_total(text)

        assert result is not None
        assert result.value == 45.67
        assert result.confidence > 0.9
        assert result.label == "TOTAL"

    def test_total_with_colon(self) -> None:
        """Test 'TOTAL: $XX.XX' pattern."""
        text = "TOTAL: $45.67"
        result = currency_matcher.extract_total(text)

        assert result is not None
        assert result.value == 45.67

    def test_total_without_dollar_sign(self) -> None:
        """Test 'TOTAL 45.67' pattern."""
        text = "TOTAL 45.67"
        result = currency_matcher.extract_total(text)

        assert result is not None
        assert result.value == 45.67

    def test_amount_due(self) -> None:
        """Test 'AMOUNT DUE' pattern."""
        text = "AMOUNT DUE: $45.67"
        result = currency_matcher.extract_total(text)

        assert result is not None
        assert result.value == 45.67
        assert result.label == "AMOUNT DUE"

    def test_sale_pattern(self) -> None:
        """Test 'SALE $XX.XX' pattern."""
        text = "SALE $45.67"
        result = currency_matcher.extract_total(text)

        assert result is not None
        assert result.value == 45.67

    def test_grand_total(self) -> None:
        """Test 'GRAND TOTAL' pattern."""
        text = "GRAND TOTAL $45.67"
        result = currency_matcher.extract_total(text)

        assert result is not None
        assert result.value == 45.67
        assert result.label == "GRAND TOTAL"

    def test_total_sale(self) -> None:
        """Test 'TOTAL SALE' pattern."""
        text = "TOTAL SALE: $45.67"
        result = currency_matcher.extract_total(text)

        assert result is not None
        assert result.value == 45.67

    def test_balance_due(self) -> None:
        """Test 'BALANCE DUE' pattern."""
        text = "BALANCE DUE $45.67"
        result = currency_matcher.extract_total(text)

        assert result is not None
        assert result.value == 45.67

    def test_multiple_amounts_picks_total(self) -> None:
        """Test that labeled total is preferred over generic amounts."""
        text = """
        REGULAR 87
        10.500 GAL @ $3.67
        SUBTOTAL $38.54
        TAX $0.00
        TOTAL $38.54
        """
        result = currency_matcher.extract_total(text)

        assert result is not None
        assert result.value == 38.54
        assert result.pattern_name == "total_explicit"

    def test_all_amounts(self) -> None:
        """Test extracting all amounts from receipt."""
        text = """
        SUBTOTAL $35.00
        TAX $3.54
        TOTAL $38.54
        """
        results = currency_matcher.extract_all_amounts(text)

        # Should find TOTAL and possibly others
        assert len(results) >= 1
        assert any(r.value == 38.54 for r in results)

    def test_comma_thousand_separator(self) -> None:
        """Test amounts with thousand separators."""
        text = "TOTAL $1,234.56"
        result = currency_matcher.extract_total(text)

        assert result is not None
        assert result.value == 1234.56

    def test_reasonable_total_range(self) -> None:
        """Test that unreasonable totals are filtered."""
        # Very small amount
        text = "TOTAL $0.05"
        result = currency_matcher.extract_total(text)
        assert result is None  # Too small for fuel receipt

        # Reasonable amount
        text = "TOTAL $45.67"
        result = currency_matcher.extract_total(text)
        assert result is not None

    def test_receipt_context_extraction(self) -> None:
        """Test extraction from realistic receipt text."""
        text = """
        SHELL
        123 MAIN ST
        DATE: 01/15/2024

        UNLEADED 87
        10.500 GAL
        @ $3.679/GAL

        FUEL TOTAL    $38.63
        TAX           $0.00
        TOTAL         $38.63

        DEBIT CARD
        ************1234
        """
        result = currency_matcher.extract_total(text)

        assert result is not None
        assert result.value == 38.63

    def test_no_total_returns_largest(self) -> None:
        """Test fallback to largest amount when no labeled total."""
        text = """
        $10.50
        $5.00
        $45.67
        """
        result = currency_matcher.extract_total(text)

        # Should infer largest reasonable amount as total
        assert result is not None
        assert result.value == 45.67
        assert result.confidence < 0.7  # Lower confidence for inferred

    def test_no_amounts_returns_none(self) -> None:
        """Test that text without amounts returns None."""
        text = "SHELL STATION\nPUMP 5"
        result = currency_matcher.extract_total(text)

        assert result is None


class TestEdgeCases:
    """Test edge cases in currency parsing."""

    def test_european_format(self) -> None:
        """Test European format (comma as decimal)."""
        # European: 45,67 means 45.67
        text = "TOTAL 45,67"
        result = currency_matcher.extract_total(text)

        assert result is not None
        assert result.value == 45.67

    def test_spaces_in_amount(self) -> None:
        """Test handling of spaces around amounts."""
        text = "TOTAL $ 45.67"
        result = currency_matcher.extract_total(text)

        assert result is not None
        assert result.value == 45.67

    def test_case_insensitive(self) -> None:
        """Test case insensitive matching."""
        for label in ["TOTAL", "Total", "total"]:
            text = f"{label} $45.67"
            result = currency_matcher.extract_total(text)

            assert result is not None, f"Failed for {label}"
            assert result.value == 45.67
