"""API tests for transaction 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.transactions.models import Transaction
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 TransactionApiTests(APITestCase):
    def setUp(self) -> None:
        self.user = User.objects.create_user(
            telegram_user_id=9001,
            first_name="TxUser",
            username="txuser",
        )
        self.client = APIClient()
        self.client.force_authenticate(user=self.user)

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

    def test_list_is_scoped_to_authenticated_user(self):
        """Authenticated user only sees their own transactions."""
        other_user = User.objects.create_user(
            telegram_user_id=9002, first_name="Other", username="other"
        )
        tx_user = Transaction.objects.create(
            user=self.user,
            transaction_type=Transaction.TYPE_REWARD,
            amount=Decimal("5.00000000"),
            status=Transaction.STATUS_COMPLETED,
            balance_before=Decimal("0"),
            balance_after=Decimal("5.00000000"),
        )
        Transaction.objects.create(
            user=other_user,
            transaction_type=Transaction.TYPE_WITHDRAWAL,
            amount=Decimal("2.00000000"),
            status=Transaction.STATUS_COMPLETED,
            balance_before=Decimal("10.00000000"),
            balance_after=Decimal("8.00000000"),
        )

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

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

    def test_filter_by_transaction_type(self):
        """GET /transactions supports filtering by transaction type."""
        Transaction.objects.create(
            user=self.user,
            transaction_type=Transaction.TYPE_COMMISSION,
            amount=Decimal("3.00000000"),
            status=Transaction.STATUS_COMPLETED,
            balance_before=Decimal("0"),
            balance_after=Decimal("3.00000000"),
        )
        reward_tx = Transaction.objects.create(
            user=self.user,
            transaction_type=Transaction.TYPE_REWARD,
            amount=Decimal("1.00000000"),
            status=Transaction.STATUS_COMPLETED,
            balance_before=Decimal("3.00000000"),
            balance_after=Decimal("4.00000000"),
        )

        url = reverse("transaction-list")
        response = self.client.get(url, {"type": Transaction.TYPE_REWARD})

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

    def test_filter_unknown_type_returns_empty_list(self):
        """Unknown type filter should not error and returns empty set."""
        Transaction.objects.create(
            user=self.user,
            transaction_type=Transaction.TYPE_REWARD,
            amount=Decimal("1.00000000"),
            status=Transaction.STATUS_COMPLETED,
            balance_before=Decimal("0"),
            balance_after=Decimal("1.00000000"),
        )

        url = reverse("transaction-list")
        response = self.client.get(url, {"type": "nonexistent"})

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

    def test_list_orders_descending_by_created_at(self):
        """Most recent transactions should appear first."""
        older = Transaction.objects.create(
            user=self.user,
            transaction_type=Transaction.TYPE_REWARD,
            amount=Decimal("1.00000000"),
            status=Transaction.STATUS_COMPLETED,
            balance_before=Decimal("0"),
            balance_after=Decimal("1.00000000"),
        )
        Transaction.objects.filter(id=older.id).update(
            created_at=timezone.now() - timedelta(days=1)
        )
        newer = Transaction.objects.create(
            user=self.user,
            transaction_type=Transaction.TYPE_WITHDRAWAL,
            amount=Decimal("2.00000000"),
            status=Transaction.STATUS_COMPLETED,
            balance_before=Decimal("1.00000000"),
            balance_after=Decimal("-1.00000000"),
        )

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

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        results = get_results(response.data)
        self.assertEqual([tx["id"] for tx in results], [newer.id, older.id])

    def test_retrieve_other_users_transaction_returns_404(self):
        """User cannot access another user's transaction detail."""
        other_user = User.objects.create_user(
            telegram_user_id=9999, first_name="Other", username="otheruser"
        )
        other_tx = Transaction.objects.create(
            user=other_user,
            transaction_type=Transaction.TYPE_DEPOSIT,
            amount=Decimal("5.00000000"),
            status=Transaction.STATUS_COMPLETED,
            balance_before=Decimal("0"),
            balance_after=Decimal("5.00000000"),
        )

        url = reverse("transaction-detail", args=[other_tx.id])
        response = self.client.get(url)

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

    def test_returns_metadata_fields(self):
        """Serializer should include blockchain/hash/data fields."""
        tx = Transaction.objects.create(
            user=self.user,
            transaction_type=Transaction.TYPE_DEPOSIT,
            amount=Decimal("3.00000000"),
            status=Transaction.STATUS_PENDING,
            balance_before=Decimal("0"),
            balance_after=Decimal("3.00000000"),
            blockchain="tron",
            transaction_hash="0xabc",
            data={"explorer_link": "https://explorer/0xabc", "note": "test"},
        )

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

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        result = get_results(response.data)[0]
        self.assertEqual(result["id"], tx.id)
        self.assertEqual(result["blockchain"], "tron")
        self.assertEqual(result["transaction_hash"], "0xabc")
        self.assertEqual(result["data"]["note"], "test")
