from seller import models as sellerModel
from rest_framework import serializers
from django.db.models import Sum, Max
from user import models as userModel
from django.utils import timezone
from . import models as saleModel
from setting import models as settingModel
from django.db.models import F


class InquirySerializer(serializers.ModelSerializer):
    product_name = serializers.CharField(source='product.name', read_only=True)
    unit = serializers.CharField(source='product.count_type', read_only=True)

    class Meta:
        model = saleModel.Inquiry
        fields = ('id', 'product', 'product_name', 'originality', 'count', 'unit')
        read_only_fields = ('id', 'product_name', 'unit')


class TempInquirySerializer(serializers.ModelSerializer):
    product_name = serializers.CharField(source='product.name', read_only=True)
    unit = serializers.CharField(source='product.count_type', read_only=True)

    class Meta:
        model = saleModel.Inquiry
        fields = ('id', 'product', 'product_name', 'unit')
        read_only_fields = ('id', 'product_name', 'unit')


class InquiryBoxSerializer(serializers.ModelSerializer):
    inquiries = InquirySerializer(many=True, required=True)
    car_name = serializers.CharField(source='car.name', read_only=True)
    brand = serializers.IntegerField(source='car.brand_id', read_only=True)
    VINRequired = serializers.BooleanField(source='car.brand.VINRequired', read_only=True)

    @staticmethod
    def get_remain_time(obj):
        if obj.temp:
            return None

        remain = settingModel.SiteSetting.get_solo().inquiry_time * 60 - (timezone.now() - obj.created).seconds
        if remain >= 0:
            return remain
        elif remain >= - (3600 * 9):  # last 9 hour
            return 0
        else:
            return -1

    remain_time = serializers.SerializerMethodField("get_remain_time")

    class Meta:
        model = saleModel.InquiryBox
        fields = ('id', 'VIN', 'engine_volume', 'production_year', 'type', 'brand', 'VINRequired', 'car', 'car_name',
                  'customer', 'jalali_created', 'created', 'inquiries', 'remain_time', 'temp')
        read_only_fields = ('customer', 'created', 'jalali_created', 'car_name', 'remain_time', 'temp', 'brand', 'VINRequired')

    def create(self, validated_data):
        if not validated_data['temp']:
            inquiries = validated_data.pop('inquiries')
            inquiry_box = saleModel.InquiryBox.objects.create(**validated_data)
            for inquiry in inquiries:
                saleModel.Inquiry.objects.create(inquiry_box=inquiry_box, **inquiry)
        else:
            inquiry_box = self._update_inquiry_box(validated_data)

        return inquiry_box

    def _update_inquiry_box(self, box):
        exist_box = saleModel.InquiryBox.objects.filter(
            car=box['car'],
            customer=box['customer_id'],
            temp=True
        ).first()
        if exist_box:
            exist_box.type = box['type']
            exist_box.production_year = box['production_year']
            exist_box.engine_volume = box['engine_volume']
            exist_box.VIN = box['VIN']
            exist_box.temp = False
            exist_box.created = timezone.now()

            for inquiry in box['inquiries']:
                exist_inquiry = saleModel.Inquiry.objects.filter(
                    inquiry_box_id=exist_box.id,
                    product_id=inquiry['product']
                ).first()
                if exist_inquiry:
                    exist_inquiry.originality = inquiry['originality']
                    exist_inquiry.count = inquiry['count']
                    exist_inquiry.save()

            exist_box.save()
            return exist_box

        raise serializers.ValidationError({"error": "از این سبد قبلا استعلام گرفته شده است"})


    def to_representation(self, instance):
        ret = super(InquiryBoxSerializer, self).to_representation(instance)
        queryset = saleModel.Inquiry.objects.filter(inquiry_box_id=instance.id)
        serializer = InquirySerializer(queryset, many=True)
        data = serializer.data
        extra_ret = {
            'inquiries': data
        }
        ret.update(extra_ret)
        return ret


class TempInquiryBoxSerializer(serializers.ModelSerializer):
    inquiry = TempInquirySerializer(required=True, write_only=True)
    car_name = serializers.CharField(source='car.name', read_only=True)
    brand = serializers.IntegerField(source='car.brand_id', read_only=True)
    VINRequired = serializers.BooleanField(source='car.brand.VINRequired', read_only=True)

    class Meta:
        model = saleModel.InquiryBox
        fields = ('id', 'brand', 'VINRequired', 'car', 'car_name', 'customer', 'jalali_created', 'created', 'inquiry')
        read_only_fields = ('customer', 'created', 'jalali_created', 'car_name', 'brand', 'VINRequired')

    def create(self, validated_data):
        inquiry = validated_data.pop('inquiry')
        inquiry_box = saleModel.InquiryBox.objects.filter(
            car=validated_data.get('car'),
            customer=validated_data.get('customer_id'),
            temp=True
        ).first()
        if not inquiry_box:
            inquiry_box = saleModel.InquiryBox.objects.create(**validated_data)

        exist_inquiry = saleModel.Inquiry.objects.filter(inquiry_box=inquiry_box, product_id=inquiry['product'])
        if not exist_inquiry:
            saleModel.Inquiry.objects.create(inquiry_box=inquiry_box, **inquiry)

        return inquiry_box

    def to_representation(self, instance):
        ret = super(TempInquiryBoxSerializer, self).to_representation(instance)
        queryset = saleModel.Inquiry.objects.filter(inquiry_box_id=instance.id)
        serializer = InquirySerializer(queryset, many=True)
        data = serializer.data
        extra_ret = {
            'inquiries': data
        }
        ret.update(extra_ret)
        return ret


class InquiryBoxesSerializer(serializers.Serializer):
    boxes = InquiryBoxSerializer(many=True)

    def create(self, validated_data):
        boxes_data = validated_data.get('boxes')
        customer = validated_data.get('customer_id')
        temp = validated_data.get('temp')
        boxes_data = [dict(box_data, **{'customer_id': customer, 'temp': temp, 'created': timezone.now()}) for box_data in boxes_data]
        boxes = InquiryBoxSerializer(data=boxes_data, many=True).create(boxes_data)
        obj = {'boxes': boxes}
        return obj


class NotificationSerializer(serializers.ModelSerializer):
    @staticmethod
    def get_inquiry(obj):
        return {
            "id": obj.inquiry.id,
            "product": obj.inquiry.product.name,
            "unit": obj.inquiry.product.count_type,
            "originality": obj.inquiry.originality,
            "count": obj.inquiry.count,
            "date_time": obj.inquiry.inquiry_box.jalali_created(),
            "car_info": {
                "car": obj.inquiry.inquiry_box.car.name,
                "type": obj.inquiry.inquiry_box.type,
                "VIN": obj.inquiry.inquiry_box.VIN,
                "production_year": obj.inquiry.inquiry_box.production_year,
                "engine_volume": obj.inquiry.inquiry_box.engine_volume,
            }
        }

    @staticmethod
    def get_remain_time(obj):
        return settingModel.SiteSetting.get_solo().inquiry_time * 60 - (
                timezone.now() - obj.inquiry.inquiry_box.created).seconds

    inquiry = serializers.SerializerMethodField("get_inquiry")
    remain_time = serializers.SerializerMethodField("get_remain_time")

    class Meta:
        model = saleModel.SuggestedPrices
        fields = ('id', 'inquiry', 'price', 'total_price', 'jalali_delivery_time', 'delivery_time', 'seller', 'created',
                  'remain_time')
        read_only_fields = ('id', 'product_name', 'remain_time', 'jalali_delivery_time')


class InquiriesSerializer(serializers.ModelSerializer):
    @staticmethod
    def get_inquiry(obj):
        return {
            "id": obj.inquiry.id,
            "product": obj.inquiry.product.name,
            "unit": obj.inquiry.product.count_type,
            "originality": obj.inquiry.originality,
            "count": obj.inquiry.count,
            "date_time": obj.inquiry.inquiry_box.jalali_created(),
            "car_info": {
                "car": obj.inquiry.inquiry_box.car.name,
                "type": obj.inquiry.inquiry_box.type,
                "VIN": obj.inquiry.inquiry_box.VIN,
                "production_year": obj.inquiry.inquiry_box.production_year,
                "engine_volume": obj.inquiry.inquiry_box.engine_volume,
            }
        }

    inquiry = serializers.SerializerMethodField("get_inquiry")

    class Meta:
        model = saleModel.SuggestedPrices
        fields = ('id', 'inquiry', 'price', 'total_price', 'jalali_delivery_time', 'delivery_time', 'seller', 'created')


class SuggestedPricesSerializer(serializers.ModelSerializer):
    @staticmethod
    def get_price(obj):
        return obj.get_final_price()

    @staticmethod
    def get_total_price(obj):
        return obj.get_final_total_price()

    price = serializers.SerializerMethodField("get_price")
    total_price = serializers.SerializerMethodField("get_total_price")

    class Meta:
        model = saleModel.SuggestedPrices
        fields = ('id', 'inquiry', 'price', 'total_price', 'jalali_delivery_time', 'delivery_time', 'seller', 'status',
                  'jalali_created')
        read_only_fields = ('id', 'seller', 'inquiry', 'jalali_created', 'jalali_delivery_time')


class PriceBasisSerializer(serializers.ModelSerializer):
    @staticmethod
    def get_suggested(obj):
        return {
            "id": obj.suggested.id,
            "product": obj.suggested.inquiry.product.name,
            "originality": obj.suggested.inquiry.originality,
            "count": obj.suggested.inquiry.count,
            "car_info": {
                "car": obj.suggested.inquiry.inquiry_box.car.name,
                "type": obj.suggested.inquiry.inquiry_box.type,
                "production_year": obj.suggested.inquiry.inquiry_box.production_year,
                "engine_volume": obj.suggested.inquiry.inquiry_box.engine_volume,
            },
            "price": obj.suggested.get_final_price(),
            "total_price": obj.suggested.get_final_total_price(),
            "delivery_time": obj.suggested.delivery_time,
            "jalali_delivery_time": obj.suggested.jalali_delivery_time(),
        }

    suggested = serializers.SerializerMethodField("get_suggested")

    class Meta:
        model = saleModel.PriceBasis
        fields = ('id', 'suggested', 'stock', 'jalali_created', 'jalali_expired')
        read_only_fields = ('id', 'suggested', 'jalali_created', 'jalali_expired')


class SuggestedSerializer(serializers.ModelSerializer):
    class Meta:
        model = saleModel.SuggestedPrices
        fields = ('id', 'inquiry', 'price', 'total_price', 'jalali_delivery_time', 'delivery_time', 'seller', 'status',
                  'jalali_created')
        read_only_fields = ('id', 'inquiry', 'seller', 'status', 'jalali_created', 'jalali_delivery_time')

    def update(self, instance, validated_data):
        if instance.inquiry.inquiry_box.created >= timezone.now() - timezone.timedelta(
                minutes=settingModel.SiteSetting.get_solo().inquiry_time):
            return super(SuggestedSerializer, self).update(instance, validated_data)
        raise serializers.ValidationError("زمان قیمت دهی به پایان رسیده است")


class CompetitionSerializer(serializers.ModelSerializer):
    suggested = SuggestedSerializer(required=True)

    class Meta:
        model = saleModel.PriceBasis
        fields = ('id', 'stock', 'suggested', 'jalali_created', 'jalali_expired')
        read_only_fields = ('id', 'jalali_created', 'jalali_expired')
        depth = 1

    def create(self, validated_data):
        suggested_data = validated_data.pop('suggested')
        prev_base = saleModel.PriceBasis.objects.get(pk=validated_data.pop('base_id'))
        fields = sellerModel.Fields.objects.filter(seller_id=validated_data['seller_id'],
                                                   car=prev_base.suggested.inquiry.inquiry_box.car,
                                                   product=prev_base.suggested.inquiry.product)
        if fields:
            if suggested_data['total_price'] < prev_base.suggested.total_price:
                price_algorithm = True
                if prev_base.suggested.total_price < 100000:
                    if suggested_data['total_price'] % 5000 != 0:
                        price_algorithm = False
                elif prev_base.suggested.total_price < 1000000:
                    if suggested_data['total_price'] % 10000 != 0:
                        price_algorithm = False
                else:
                    if suggested_data['total_price'] % 50000 != 0:
                        price_algorithm = False
                if price_algorithm:
                    prev_base.expired = timezone.now()
                    prev_base.save()
                    suggested = saleModel.SuggestedPrices.objects.create(seller_id=validated_data.pop('seller_id'),
                                                                         status='competition',
                                                                         inquiry=prev_base.suggested.inquiry,
                                                                         created=timezone.now(), accepted=True,
                                                                         **suggested_data)
                    base = saleModel.PriceBasis.objects.create(suggested=suggested,
                                                               expired=timezone.now() + timezone.timedelta(hours=24),
                                                               **validated_data)
                    return base
                raise serializers.ValidationError({"error": "الگوریتم قیمت دهی رعایت نشده است"})
            raise serializers.ValidationError({"error": "قیمت وارد شده قابل رقابت نیست"})
        raise serializers.ValidationError({"error": "این مورد در زمینه های کاری شما ثبت نشده است"})


class ListOrderDetailsSerializer(serializers.ModelSerializer):
    @staticmethod
    def get_inquiry(obj):
        return {
            "id": obj.inquiry.id,
            "product": obj.inquiry.product.name,
            "unit": obj.inquiry.product.count_type,
            "originality": obj.inquiry.originality,
            "count": obj.inquiry.count,
            "date_time": obj.order.jalali_created(),
            "car_info": {
                "car": obj.inquiry.inquiry_box.car.name,
                "type": obj.inquiry.inquiry_box.type,
                "VIN": obj.inquiry.inquiry_box.VIN,
                "production_year": obj.inquiry.inquiry_box.production_year,
                "engine_volume": obj.inquiry.inquiry_box.engine_volume,
            }
        }

    def get_price(self, obj):
        if 'request' in self.context:
            user = userModel.User.objects.get(id=self.context['request'].user.id)
            if user.get_user_type() == 'seller':
                return obj.suggested.price
        return obj.suggested.get_final_price()

    def get_total_price(self, obj):
        if 'request' in self.context:
            user = userModel.User.objects.get(id=self.context['request'].user.id)
            if user.get_user_type() == 'seller':
                return obj.suggested.total_price
        return obj.suggested.get_final_total_price()

    @staticmethod
    def get_delivery_time(obj):
        return obj.suggested.delivery_time

    @staticmethod
    def get_jalali_delivery_time(obj):
        return obj.suggested.jalali_delivery_time()

    inquiry = serializers.SerializerMethodField("get_inquiry")
    price = serializers.SerializerMethodField("get_price")
    total_price = serializers.SerializerMethodField("get_total_price")
    delivery_time = serializers.SerializerMethodField("get_delivery_time")
    jalali_delivery_time = serializers.SerializerMethodField("get_jalali_delivery_time")

    class Meta:
        model = saleModel.OrderDetails
        fields = ('id', 'inquiry', 'price', 'total_price', 'off', 'jalali_delivery_time', 'delivery_time', 'suggested')
        read_only_fields = ('id', 'price', 'off', 'suggested', 'jalali_delivery_time')


class ListOrderSerializer(serializers.ModelSerializer):
    @staticmethod
    def get_total_price(obj):
        return obj.order_details.aggregate(Sum('price'))['price__sum']

    @staticmethod
    def get_total_payable(obj):
        total = obj.order_details.aggregate(total_payable=Sum(F('price') * ((100 - F('off')) / 100)))['total_payable']
        return int(total or 0) + (obj.post_price or 0)

    order_details = ListOrderDetailsSerializer(many=True, required=True)
    total_price = serializers.SerializerMethodField("get_total_price")
    total_payable = serializers.SerializerMethodField("get_total_payable")

    class Meta:
        model = saleModel.Orders
        fields = ('id', 'status', 'order_details', 'jalali_created', 'post_price', 'total_price', 'total_payable')
        read_only_fields = ('id', 'jalali_created', 'status', 'total_price', 'post_price', 'total_payable')


class OrderDetailsSerializer(serializers.ModelSerializer):
    class Meta:
        model = saleModel.OrderDetails
        fields = ('id', 'inquiry', 'suggested')
        read_only_fields = ('id',)


class OrderSerializer(serializers.ModelSerializer):
    @staticmethod
    def get_total_price(obj):
        return obj.order_details.aggregate(Sum('price'))['price__sum']

    @staticmethod
    def get_total_payable(obj):
        total = obj.order_details.aggregate(total_payable=Sum(F('price') * ((100 - F('off')) / 100)))['total_payable']
        return int(total or 0) + (obj.post_price or 0)

    # @staticmethod
    # def get_delivery_time(obj):
    #     return obj.order_details.suggested.aggregate(Max('delivery_time'))['delivery_time_max']

    order_details = OrderDetailsSerializer(many=True, required=True)
    total_price = serializers.SerializerMethodField("get_total_price")
    total_payable = serializers.SerializerMethodField("get_total_payable")

    class Meta:
        model = saleModel.Orders
        fields = ('id', 'status', 'order_details', 'jalali_created', 'post_price', 'total_price', 'total_payable')
        read_only_fields = ('id', 'jalali_created', 'status', 'total_price', 'post_price', 'total_payable')

    def create(self, validated_data):
        order_details = validated_data.pop('order_details')
        order = saleModel.Orders.objects.create(**validated_data)
        # order.delivery_time = self.get_delivery_time()
        for detail in order_details:
            if detail['inquiry'] == detail['suggested'].inquiry:
                detail['price'] = detail['suggested'].get_final_total_price()
                off = detail['suggested'].get_discount()
                saleModel.OrderDetails.objects.create(order=order, off=off, **detail)
            else:
                raise serializers.ValidationError("خطا در ثبت خرید")
        return order

    def to_representation(self, instance):
        ret = super(OrderSerializer, self).to_representation(instance)
        queryset = saleModel.OrderDetails.objects.filter(order_id=instance.id)
        serializer = ListOrderDetailsSerializer(queryset, many=True)
        data = serializer.data
        extra_ret = {
            'order_details': data
        }
        ret.update(extra_ret)
        return ret


class AddressOrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = saleModel.Orders
        fields = ('id', 'status', 'address', 'post_price', 'jalali_updated')  # delivery_time
        read_only_fields = ('id', 'status', 'post_price', 'jalali_updated')

    def update(self, instance, validated_data):
        address = userModel.Address.objects.get(id=validated_data['address'].id)
        if address.user == instance.user:
            instance.post_price = 0
            # if address.province == 8:
            #     instance.post_price = 20000
            # else:
            #     instance.post_price = 30000
            return super(AddressOrderSerializer, self).update(instance, validated_data)
        raise serializers.ValidationError("خطا در انتخاب آدرس")

    def to_representation(self, obj):
        return OrderSerializer(obj).data
