import random
import string
from decimal import Decimal

from rest_framework import serializers

from .models import Deal


TIMELINE_STATUSES = [
    Deal.Status.DRAFT,
    Deal.Status.AWAITING_PAYMENT,
    Deal.Status.FUNDED,
    Deal.Status.IN_TRANSIT,
    Deal.Status.CONFIRMING,
    Deal.Status.COMPLETED,
]


class UserSummarySerializer(serializers.Serializer):
    id = serializers.UUIDField()
    phone = serializers.CharField()
    name = serializers.CharField(allow_null=True)


class DealSerializer(serializers.ModelSerializer):
    seller = serializers.SerializerMethodField()
    buyer = serializers.SerializerMethodField()
    status_timeline = serializers.SerializerMethodField()
    available_actions = serializers.SerializerMethodField()
    can_join = serializers.SerializerMethodField()

    class Meta:
        model = Deal
        fields = [
            "id",
            "code",
            "title",
            "description",
            "amount",
            "fee",
            "net_amount",
            "status",
            "inspection_window_hours",
            "tracking_info",
            "funded_at",
            "shipped_at",
            "confirmed_at",
            "auto_release_at",
            "has_dispute",
            "seller",
            "buyer",
            "status_timeline",
            "available_actions",
            "can_join",
        ]

    def get_seller(self, obj):
        return {
            "id": obj.seller.id,
            "phone": obj.seller.phone,
            "name": obj.seller.name,
        }

    def get_buyer(self, obj):
        if obj.buyer is None:
            return None
        return {
            "id": obj.buyer.id,
            "phone": obj.buyer.phone,
            "name": obj.buyer.name,
        }

    def get_status_timeline(self, obj):
        current_index = TIMELINE_STATUSES.index(obj.status) if obj.status in TIMELINE_STATUSES else -1
        timeline = []

        for index, key in enumerate(TIMELINE_STATUSES):
            reached = False
            if key == Deal.Status.DRAFT:
                reached = True
            elif key == Deal.Status.AWAITING_PAYMENT:
                reached = bool(obj.buyer) or current_index >= index
            elif key == Deal.Status.FUNDED:
                reached = bool(obj.funded_at) or current_index >= index
            elif key == Deal.Status.IN_TRANSIT:
                reached = bool(obj.shipped_at) or current_index >= index
            elif key == Deal.Status.CONFIRMING:
                reached = current_index >= index
            elif key == Deal.Status.COMPLETED:
                reached = bool(obj.confirmed_at) or current_index >= index

            timeline.append(
                {
                    "key": key,
                    "label": Deal.Status(key).label,
                    "reached": reached,
                    "current": obj.status == key,
                }
            )

        return timeline

    def get_available_actions(self, obj):
        user = self.context.get("user")
        if user is None:
            return []

        actions = []
        is_seller = obj.seller_id == user.id
        is_buyer = obj.buyer_id == user.id

        if is_buyer and obj.status == Deal.Status.AWAITING_PAYMENT:
            actions.append("fund")

        if is_seller and obj.status == Deal.Status.FUNDED:
            actions.append("ship")

        if is_buyer and obj.status in {Deal.Status.IN_TRANSIT, Deal.Status.CONFIRMING}:
            actions.append("confirm")

        if (is_seller or is_buyer) and obj.status in {
            Deal.Status.AWAITING_PAYMENT,
            Deal.Status.FUNDED,
            Deal.Status.IN_TRANSIT,
            Deal.Status.CONFIRMING,
        } and not obj.has_dispute:
            actions.append("dispute")

        return actions

    def get_can_join(self, obj):
        user = self.context.get("user")
        if user is None:
            return False
        if obj.buyer_id is not None:
            return obj.buyer_id == user.id
        return obj.seller_id != user.id and obj.status in {Deal.Status.DRAFT, Deal.Status.AWAITING_PAYMENT}


class DealCreateSerializer(serializers.ModelSerializer):
    inspection_window_hours = serializers.ChoiceField(choices=[24, 48, 72, 120])

    class Meta:
        model = Deal
        fields = ["title", "description", "amount", "inspection_window_hours"]

    def validate_amount(self, value):
        if value <= Decimal("0"):
            raise serializers.ValidationError("amount must be greater than 0")
        return value

    def create(self, validated_data):
        seller = self.context["seller"]
        amount = validated_data["amount"]
        fee = Decimal("0.00")
        return Deal.objects.create(
            seller=seller,
            code=self._generate_unique_deal_code(),
            title=validated_data["title"],
            description=validated_data["description"],
            amount=amount,
            fee=fee,
            net_amount=amount - fee,
            status=Deal.Status.DRAFT,
            inspection_window_hours=validated_data["inspection_window_hours"],
        )

    def _generate_unique_deal_code(self):
        alphabet = string.ascii_uppercase + string.digits
        for _ in range(20):
            code = "".join(random.choices(alphabet, k=8))
            if not Deal.objects.filter(code=code).exists():
                return code
        raise serializers.ValidationError("Failed to generate unique deal code. Please retry.")
