"""API tests for referral commission endpoints."""

from __future__ import annotations

from datetime import timedelta
from decimal import Decimal

from django.urls import reverse
from django.utils import timezone
from rest_framework import status
from rest_framework.test import APIClient, APITestCase

from apps.investments.models import Investment, Reward
from apps.referrals.models import Commission
from apps.users.models import User


def get_results(payload):
    """Handle paginated and non-paginated DRF responses."""
    if isinstance(payload, dict) and "results" in payload:
        return payload["results"]
    return payload


class CommissionApiTests(APITestCase):
    def setUp(self) -> None:
        self.upline = User.objects.create_user(
            telegram_user_id=8001,
            first_name="Upline",
            username="upline",
        )
        self.downline = User.objects.create_user(
            telegram_user_id=8002,
            first_name="Downline",
            username="downline",
            referred_by=self.upline,
        )
        self.other_upline = User.objects.create_user(
            telegram_user_id=8003,
            first_name="Other",
            username="other",
        )

        tier_info = Investment.get_tier_info(Decimal("100"))
        now = timezone.now()
        investment = Investment.objects.create(
            user=self.downline,
            amount=Decimal("100"),
            tier=tier_info["tier"],
            daily_reward_rate=tier_info["rate"],
            duration_days=tier_info["duration"],
            status=Investment.STATUS_ACTIVE,
            start_date=now,
            end_date=now + timedelta(days=tier_info["duration"]),
        )
        reward = Reward.objects.create(
            investment=investment,
            amount=Decimal("2.00000000"),
            reward_date=now.date(),
        )

        self.pending_commission = Commission.objects.create(
            upline_user=self.upline,
            downline_user=self.downline,
            reward=reward,
            level=1,
            commission_rate=Decimal("50.00"),
            amount=Decimal("1.00000000"),
            status=Commission.STATUS_PENDING,
        )
        self.distributed_commission = Commission.objects.create(
            upline_user=self.upline,
            downline_user=self.downline,
            reward=reward,
            level=2,
            commission_rate=Decimal("30.00"),
            amount=Decimal("0.60000000"),
            status=Commission.STATUS_DISTRIBUTED,
        )
        Commission.objects.create(
            upline_user=self.other_upline,
            downline_user=self.downline,
            reward=reward,
            level=3,
            commission_rate=Decimal("20.00"),
            amount=Decimal("0.40000000"),
            status=Commission.STATUS_PENDING,
        )

        self.client = APIClient()
        self.client.force_authenticate(user=self.upline)

    def test_requires_authentication(self):
        """Unauthenticated requests are rejected."""
        client = APIClient()
        response = client.get(reverse("commission-list"))
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    def test_commissions_are_scoped_to_upline_user(self):
        """Authenticated user only sees commissions they earned."""
        response = self.client.get(reverse("commission-list"))

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        results = get_results(response.data)
        self.assertEqual(len(results), 2)
        returned_ids = {item["id"] for item in results}
        self.assertSetEqual(
            returned_ids,
            {self.pending_commission.id, self.distributed_commission.id},
        )

    def test_filter_by_status(self):
        """GET /commissions supports filtering by status."""
        url = reverse("commission-list")
        response = self.client.get(url, {"status": Commission.STATUS_DISTRIBUTED})

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        results = get_results(response.data)
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0]["id"], self.distributed_commission.id)

    def test_filter_unknown_status_returns_empty_list(self):
        """Unknown status filter yields an empty list instead of error."""
        response = self.client.get(
            reverse("commission-list"), {"status": "does-not-exist"}
        )

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(get_results(response.data)), 0)

    def test_orders_commissions_descending_by_created_at(self):
        """Default ordering is newest first by created_at."""
        older_commission = Commission.objects.create(
            upline_user=self.upline,
            downline_user=self.downline,
            reward=self.pending_commission.reward,
            level=3,
            commission_rate=Decimal("20.00"),
            amount=Decimal("0.20000000"),
            status=Commission.STATUS_PENDING,
        )
        Commission.objects.filter(id=older_commission.id).update(
            created_at=timezone.now() - timedelta(days=1)
        )

        response = self.client.get(reverse("commission-list"))

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        results = get_results(response.data)
        returned_ids = [item["id"] for item in results]
        self.assertEqual(
            returned_ids[:2],
            [self.distributed_commission.id, self.pending_commission.id],
        )

    def test_orders_commissions_ascending_when_requested(self):
        """Ordering filter supports ascending created_at when requested."""
        Commission.objects.filter(id=self.pending_commission.id).update(
            created_at=timezone.now() - timedelta(days=1)
        )

        response = self.client.get(
            reverse("commission-list"), {"ordering": "created_at"}
        )

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        results = get_results(response.data)
        returned_ids = [item["id"] for item in results]
        self.assertEqual(
            returned_ids[:2],
            [self.pending_commission.id, self.distributed_commission.id],
        )

    def test_retrieve_other_uplines_commission_returns_404(self):
        """Detail view is scoped to authenticated upline."""
        self.client.force_authenticate(user=self.other_upline)
        response = self.client.get(
            reverse("commission-detail", args=[self.pending_commission.id])
        )

        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
