import pytest
from decimal import Decimal

from digit_counter import DigitCounter, CountingMode, DigitCounterError


class TestDigitCounterBasic:
    @pytest.fixture
    def counter(self):
        return DigitCounter(precision=15, enable_cache=True)

    def test_integer_count(self, counter):
        assert counter.count_digits(12345) == 5
        assert counter.count_digits(-999) == 3
        assert counter.count_digits(0) == 1

    def test_float_total(self, counter):
        assert counter.count_digits(123.456, mode="total") == 6
        assert counter.count_digits(10.01, mode="total") == 4

    def test_before_decimal(self, counter):
        assert counter.count_digits(123.456, mode="before") == 3
        assert counter.count_digits(0.123, mode="before") == 1

    def test_after_decimal(self, counter):
        assert counter.count_digits(123.456, mode="after") == 3
        assert counter.count_digits(1.2300, mode="after") == 2  # trimmed zeros

    def test_decimal_input(self, counter):
        value = Decimal("12345.678900")
        result = counter.count_digits(value, mode="all")
        assert result.before_decimal == 5
        assert result.after_decimal == 4

    def test_invalid_inputs(self, counter):
        with pytest.raises(DigitCounterError):
            counter.count_digits("abc")

        with pytest.raises(DigitCounterError):
            counter.count_digits("")

    def test_all_mode_returns_object(self, counter):
        result = counter.count_digits(123.45, mode="all")
        assert result.total_digits == 5
        assert result.before_decimal == 3
        assert result.after_decimal == 2
        assert result.is_integer is False

    def test_cache_usage(self):
        counter = DigitCounter(enable_cache=True)
        counter.count_digits(123)
        counter.count_digits(123)
        stats = counter.get_statistics()
        assert stats["cache_hits"] >= 1


class TestBatchProcessing:
    @pytest.fixture
    def counter(self):
        return DigitCounter()

    def test_batch_all_success(self, counter):
        values = [1, 22, 333, 4.56]
        result = counter.batch_process(values, mode="total")
        assert result.successful_items == 4
        assert result.failed_items == 0

    def test_batch_with_errors(self, counter):
        values = ["123", "bad", 456]
        result = counter.batch_process(values, mode="total", skip_errors=True)
        assert result.successful_items == 2
        assert result.failed_items == 1

    def test_batch_no_skip_errors(self, counter):
        values = [5, "oops"]
        with pytest.raises(Exception):
            counter.batch_process(values, skip_errors=False)
