"""Unit tests for UsageReport model."""

from datetime import UTC, datetime, timedelta

from augint_billing_lib.models import UsageReport


class TestUsageReport:
    """Test suite for UsageReport model."""

    def test_create_usage_report(self):
        """Test creating a basic usage report."""
        now = datetime.now(UTC)
        report = UsageReport(
            api_key_id="key_123",
            window_start=now - timedelta(hours=1),
            window_end=now,
            units_reported=1500,
            stripe_customer_id="cus_abc",
            stripe_subscription_item_id="si_xyz",
            usage_plan_id="METERED",
            stripe_idempotency_key="key_123:2024-01-15T10:00:00:2024-01-15T11:00:00",
            stripe_response={"status": "success"},
            reported_at=now,
            reported_by_request_id="req_123",
            lambda_function_version="$LATEST",
            library_version="2.6.1",
        )

        assert report.api_key_id == "key_123"
        assert report.units_reported == 1500
        assert report.stripe_customer_id == "cus_abc"

    def test_window_duration_seconds(self):
        """Test calculating window duration."""
        start = datetime(2024, 1, 15, 10, 0, 0, tzinfo=UTC)
        end = datetime(2024, 1, 15, 11, 0, 0, tzinfo=UTC)

        report = UsageReport(
            api_key_id="key_123",
            window_start=start,
            window_end=end,
            units_reported=1000,
            stripe_customer_id="cus_abc",
            stripe_subscription_item_id="si_xyz",
            usage_plan_id="METERED",
            stripe_idempotency_key="test_key",
            stripe_response={},
            reported_at=end,
            reported_by_request_id="req_123",
            lambda_function_version="$LATEST",
            library_version="2.6.1",
        )

        assert report.window_duration_seconds == 3600  # 1 hour

    def test_is_standard_hourly(self):
        """Test detecting standard hourly windows."""
        start = datetime(2024, 1, 15, 10, 0, 0, tzinfo=UTC)

        # Standard hourly window
        hourly_report = UsageReport(
            api_key_id="key_123",
            window_start=start,
            window_end=start + timedelta(hours=1),
            units_reported=1000,
            stripe_customer_id="cus_abc",
            stripe_subscription_item_id="si_xyz",
            usage_plan_id="METERED",
            stripe_idempotency_key="test_key",
            stripe_response={},
            reported_at=start + timedelta(hours=1),
            reported_by_request_id="req_123",
            lambda_function_version="$LATEST",
            library_version="2.6.1",
        )

        assert hourly_report.is_standard_hourly is True

        # Non-standard window (2 hours)
        non_hourly_report = UsageReport(
            api_key_id="key_123",
            window_start=start,
            window_end=start + timedelta(hours=2),
            units_reported=2000,
            stripe_customer_id="cus_abc",
            stripe_subscription_item_id="si_xyz",
            usage_plan_id="METERED",
            stripe_idempotency_key="test_key",
            stripe_response={},
            reported_at=start + timedelta(hours=2),
            reported_by_request_id="req_123",
            lambda_function_version="$LATEST",
            library_version="2.6.1",
        )

        assert non_hourly_report.is_standard_hourly is False

    def test_to_dynamodb_item(self):
        """Test converting report to DynamoDB item format."""
        start = datetime(2024, 1, 15, 10, 0, 0, tzinfo=UTC)
        end = datetime(2024, 1, 15, 11, 0, 0, tzinfo=UTC)
        reported_at = datetime(2024, 1, 15, 11, 5, 0, tzinfo=UTC)

        report = UsageReport(
            api_key_id="key_123",
            window_start=start,
            window_end=end,
            units_reported=1500,
            stripe_customer_id="cus_abc",
            stripe_subscription_item_id="si_xyz",
            usage_plan_id="METERED",
            stripe_idempotency_key="test_key",
            stripe_response={"status": "success"},
            stripe_usage_record_id="ur_123",
            reported_at=reported_at,
            reported_by_request_id="req_123",
            lambda_function_version="v1",
            library_version="2.6.1",
            source_usage_count=1500,
            previous_window_end=start,
        )

        item = report.to_dynamodb_item()

        # Check required fields
        assert item["api_key_id"] == "key_123"
        assert item["window_end_timestamp"] == int(end.timestamp())
        assert item["window_start_iso"] == start.isoformat()
        assert item["window_end_iso"] == end.isoformat()
        assert item["units_reported"] == 1500
        assert item["stripe_customer_id"] == "cus_abc"
        assert item["stripe_subscription_item_id"] == "si_xyz"
        assert item["usage_plan_id"] == "METERED"
        assert item["stripe_idempotency_key"] == "test_key"
        assert item["stripe_response"] == {"status": "success"}
        assert item["stripe_usage_record_id"] == "ur_123"
        assert item["reported_at_iso"] == reported_at.isoformat()
        assert item["reported_by"] == "req_123"
        assert item["lambda_function_version"] == "v1"
        assert item["library_version"] == "2.6.1"
        assert item["report_date"] == "2024-01-15"

        # Check TTL (90 days from reported_at)
        expected_ttl = int((reported_at + timedelta(days=90)).timestamp())
        assert item["ttl_timestamp"] == expected_ttl

    def test_optional_fields(self):
        """Test that optional fields can be None."""
        now = datetime.now(UTC)
        report = UsageReport(
            api_key_id="key_123",
            window_start=now - timedelta(hours=1),
            window_end=now,
            units_reported=1000,
            stripe_customer_id="cus_abc",
            stripe_subscription_item_id="si_xyz",
            usage_plan_id="METERED",
            stripe_idempotency_key="test_key",
            stripe_response={},
            stripe_usage_record_id=None,  # Optional
            reported_at=now,
            reported_by_request_id="req_123",
            lambda_function_version="$LATEST",
            library_version="2.6.1",
            source_usage_count=None,  # Optional
            previous_window_end=None,  # Optional
        )

        assert report.stripe_usage_record_id is None
        assert report.source_usage_count is None
        assert report.previous_window_end is None

        item = report.to_dynamodb_item()
        assert item["stripe_usage_record_id"] is None

    def test_immutability_through_dataclass(self):
        """Test that report fields are mutable (dataclass default behavior)."""
        now = datetime.now(UTC)
        report = UsageReport(
            api_key_id="key_123",
            window_start=now - timedelta(hours=1),
            window_end=now,
            units_reported=1000,
            stripe_customer_id="cus_abc",
            stripe_subscription_item_id="si_xyz",
            usage_plan_id="METERED",
            stripe_idempotency_key="test_key",
            stripe_response={},
            reported_at=now,
            reported_by_request_id="req_123",
            lambda_function_version="$LATEST",
            library_version="2.6.1",
        )

        # Note: Regular dataclasses are mutable by default
        # If we wanted true immutability, we'd use frozen=True
        original_units = report.units_reported
        report.units_reported = 2000
        assert report.units_reported == 2000
        assert report.units_reported != original_units
