from decimal import Decimal, InvalidOperation

import pytest
from src.__types.index import Price
from src.domain.entities.usage_event import UsageEvent


class TestUsageEvent:
    class TestCalc:
        def test_calc(self):
            """UsageEventのcalc_unitが正しいことを確認する"""
            expected_unit = Decimal("0.001")
            actual_usage_event = UsageEvent(
                code="aws.dummy.input_tokens",
                quantity=Decimal("0.1"),
                service="dummy_service",
                feature="dummy_feature",
            )
            actual_price = Price(
                code="aws.dummy.input_tokens",
                price=Decimal("0.0001"),
            )

            actual_unit = actual_usage_event.calc_unit(price=actual_price)
            assert actual_unit == expected_unit

        def test_calc_zero_quantity(self):
            """UsageEventのcalc_unitが正しいことを確認する（使用量0）"""
            expected_unit = Decimal(0)
            actual_usage_event = UsageEvent(
                code="aws.dummy.input_tokens",
                quantity=Decimal(0),
                service="dummy_service",
                feature="dummy_feature",
            )
            actual_price = Price(
                code="aws.dummy.input_tokens",
                price=Decimal("0.0001"),
            )

            actual_unit = actual_usage_event.calc_unit(price=actual_price)
            assert actual_unit == expected_unit

        def test_calc_zero_price(self):
            """UsageEventのcalc_unitが正しいことを確認する（単価0）"""
            expected_unit = Decimal(0)
            actual_usage_event = UsageEvent(
                code="aws.dummy.input_tokens",
                quantity=Decimal(100),
                service="dummy_service",
                feature="dummy_feature",
            )
            actual_price = Price(
                code="aws.dummy.input_tokens",
                price=Decimal(0),
            )

            actual_unit = actual_usage_event.calc_unit(price=actual_price)
            assert actual_unit == expected_unit

        def test_calc_zero_quantity_and_price(self):
            """UsageEventのcalc_unitが正しいことを確認する（使用量0、単価0）"""
            expected_unit = Decimal(0)
            actual_usage_event = UsageEvent(
                code="aws.dummy.input_tokens",
                quantity=Decimal(0),
                service="dummy_service",
                feature="dummy_feature",
            )
            actual_price = Price(
                code="aws.dummy.input_tokens",
                price=Decimal(0),
            )

            actual_unit = actual_usage_event.calc_unit(price=actual_price)
            assert actual_unit == expected_unit

        def test_calc_large_values(self):
            """UsageEventのcalc_unitが正しいことを確認する（大きな値）"""
            expected_unit = Decimal(10**100)
            actual_usage_event = UsageEvent(
                code="aws.dummy.input_tokens",
                quantity=Decimal(10**100),
                service="dummy_service",
                feature="dummy_feature",
            )
            actual_price = Price(
                code="aws.dummy.input_tokens",
                price=Decimal("0.01"),
            )

            with pytest.raises(InvalidOperation):
                actual_usage_event.calc_unit(price=actual_price)

        def test_calc_small_values(self):
            """UsageEventのcalc_unitが正しいことを確認する（小さな値）"""
            expected_unit = Decimal("1E-12")
            actual_usage_event = UsageEvent(
                code="aws.dummy.input_tokens",
                quantity=Decimal("1E-100"),
                service="dummy_service",
                feature="dummy_feature",
            )
            actual_price = Price(
                code="aws.dummy.input_tokens",
                price=Decimal("0.0001"),
            )

            actual_unit = actual_usage_event.calc_unit(price=actual_price)
            assert actual_unit == expected_unit
