"""Serializers for investment and reward APIs."""

from __future__ import annotations

from datetime import timedelta
from decimal import Decimal, ROUND_HALF_UP

from django.db import transaction
from django.utils import timezone
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from django_wallet_utils.exceptions import InsufficientBalanceError

from apps.transactions.models import Transaction
from utils.wallet import get_wallet_service, MAKE_INVESTMENT

from .models import Investment, Reward

DECIMAL_QUANTIZE = Decimal("0.00000001")


class InvestmentSerializer(serializers.ModelSerializer):
    """Create/read investments with tier auto-calculation."""

    class Meta:
        model = Investment
        fields = [
            "id",
            "amount",
            "tier",
            "daily_reward_rate",
            "duration_days",
            "status",
            "start_date",
            "end_date",
            "roi_total_amount",
            "roi_total_percent",
            "created_at",
            "updated_at",
        ]
        read_only_fields = [
            "tier",
            "daily_reward_rate",
            "duration_days",
            "status",
            "start_date",
            "end_date",
            "roi_total_amount",
            "roi_total_percent",
            "created_at",
            "updated_at",
        ]

    def create(self, validated_data: dict) -> Investment:
        """Derive tier, rate, and schedule from the amount."""
        user = self.context["request"].user
        tier_info = Investment.get_tier_info(validated_data["amount"])
        # start_date is created_at + 1 day (first reward calculation starts the next day)
        start_date = timezone.now() + timedelta(days=1)
        end_date = start_date + timedelta(days=tier_info["duration"])
        investment_amount = Decimal(validated_data["amount"]).quantize(
            DECIMAL_QUANTIZE, rounding=ROUND_HALF_UP
        )

        wallet_service = get_wallet_service()

        with transaction.atomic():
            # Lock user row to get consistent balance
            user_locked = user.__class__.objects.select_for_update().get(pk=user.pk)
            balance_before = user_locked.credit_balance

            # Deduct balance using wallet-utils (atomic operation with race condition prevention)
            try:
                wallet_service.deduct_point(
                    user_id=user_locked.id,
                    point_type="credit_balance",
                    amount=investment_amount,
                    remarks=f"Investment in tier {tier_info['tier']}",
                    trans_type=MAKE_INVESTMENT,
                    allow_negative=False,
                    iid=user_locked.id,  # User initiated this investment
                )
            except InsufficientBalanceError as e:
                # Format amounts with 8 decimal places to match credit_balance precision
                available = Decimal(str(e.available)) if e.available is not None else Decimal("0")
                requested = Decimal(str(e.requested)) if e.requested is not None else Decimal("0")
                available_str = f"{available:.8f}"
                requested_str = f"{requested:.8f}"
                raise ValidationError(
                    {
                        "amount": [f"Insufficient balance. Available: {available_str}, Required: {requested_str}"]
                    }
                )

            # Refresh user to get updated balance
            user_locked.refresh_from_db()
            balance_after = user_locked.credit_balance

            # Create investment
            investment = Investment.objects.create(
                user=user_locked,
                amount=validated_data["amount"],
                tier=tier_info["tier"],
                daily_reward_rate=tier_info["rate"],
                duration_days=tier_info["duration"],
                status=Investment.STATUS_PENDING,
                start_date=start_date,
                end_date=end_date,
            )

            # Create transaction record for the investment (for our own audit trail)
            Transaction.objects.create(
                user=user_locked,
                transaction_type=Transaction.TYPE_INVESTMENT,
                amount=investment_amount,
                status=Transaction.STATUS_COMPLETED,
                balance_before=balance_before,
                balance_after=balance_after,
                data={"investment_id": investment.id},
            )

            return investment


class RewardSerializer(serializers.ModelSerializer):
    """Read-only serializer for daily rewards."""
    
    daily_reward_rate = serializers.DecimalField(
        max_digits=5,
        decimal_places=2,
        source='investment.daily_reward_rate',
        read_only=True
    )

    class Meta:
        model = Reward
        fields = [
            "id",
            "investment",
            "amount",
            "reward_date",
            "daily_reward_rate",
            "calculated_at",
            "distributed_at",
        ]
        read_only_fields = fields
