from django.contrib.auth import get_user_model
from django.db import connection
from django.utils.text import slugify
from rest_framework import serializers
import json
from django.utils.translation import gettext, gettext_lazy as _
from rest_framework.generics import get_object_or_404

from AuthBillet.models import TibilletUser, HumanUser
from BaseBillet.models import Event, Price, Product, Reservation, Configuration, LigneArticle, Ticket, Paiement_stripe
from PaiementStripe.views import creation_paiement_stripe

import logging
logger = logging.getLogger(__name__)


class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = [
            "uuid",
            "name",
            "publish",
            "img",
            "categorie_article",
            "prices",
            "id_product_stripe",
        ]
        depth = 1
        read_only_fields = [
            'uuid',
            'id_product_stripe',
            'prices',
        ]


class PriceSerializer(serializers.ModelSerializer):
    product = serializers.PrimaryKeyRelatedField(queryset=Product.objects.all())

    class Meta:
        model = Price
        fields = [
            'uuid',
            'product',
            'name',
            'prix',
            'vat',
            'id_price_stripe',
            'stock',
            'max_per_user',
        ]

        read_only_fields = [
            'uuid',
            'id_price_stripe',
        ]
        depth = 1


class EventSerializer(serializers.ModelSerializer):
    products = ProductSerializer(
        many=True,
        read_only=True
    )

    class Meta:
        model = Event
        fields = [
            'uuid',
            'name',
            'slug',
            'short_description',
            'long_description',
            'event_facebook_url',
            'datetime',
            'products',
            'img',
            'reservations',
            'complet',
        ]
        read_only_fields = ['uuid', 'reservations']
        depth = 1

    def validate(self, attrs):
        # import ipdb; ipdb.set_trace()
        # slug = slugify(f"{self.initial_data.get('name')} {self.initial_data.get('datetime').strftime('%D %R')}")

        products = self.initial_data.get('products')
        if products:
            try:
                products_list = json.loads(products)
            except json.decoder.JSONDecodeError as e:
                raise serializers.ValidationError(_(f'products doit être un json valide : {e}'))

            self.products_to_db = []
            for product in products_list:
                self.products_to_db.append(get_object_or_404(Product, uuid=product.get('uuid')))
            return super().validate(attrs)
        else:
            raise serializers.ValidationError(_('products doit être un json valide'))

    def save(self, **kwargs):
        instance = super().save(**kwargs)
        instance.products.clear()
        for product in self.products_to_db:
            instance.products.add(product)
        return instance

    '''
    
    products = [
        {"uuid":"9340a9a1-1b90-488e-ab68-7b358b213dd7"},
        {"uuid":"60db1531-fd0a-4d92-a785-f384e77cd213"}
    ]
    
    
    '''


class ReservationSerializer(serializers.ModelSerializer):
    class Meta:
        model = Reservation
        fields = [
            'uuid',
            'datetime',
            'user_commande',
            'event',
            'status',
            'options',
            'tickets',
            'paiements',
        ]
        read_only_fields = [
            'uuid',
            'datetime',
            'status',
        ]
        depth = 1

class MembreshipValidator(serializers.Serializer):
    email = serializers.EmailField()

    first_name = serializers.CharField(max_length=200,)
    last_name = serializers.CharField(max_length=200,)

    phone = serializers.CharField(max_length=20, required=False)
    postal_code = serializers.IntegerField(required=False)
    birth_date = serializers.DateField(required=False)

    contribution_value = serializers.FloatField()

    def validate_email(self, value):
        User: TibilletUser = get_user_model()
        user_paiement, created = User.objects.get_or_create(
            email=value, username=value)

        if created:
            user_paiement: HumanUser
            user_paiement.client_source = connection.tenant
            user_paiement.client_achat.add(connection.tenant)
            user_paiement.is_active = False
        else:
            user_paiement.client_achat.add(connection.tenant)

        user_paiement.save()
        return user_paiement.email


class ReservationValidator(serializers.Serializer):
    email = serializers.EmailField()
    event = serializers.PrimaryKeyRelatedField(queryset=Event.objects.all())
    prices = serializers.JSONField(required=True)

    def validate_email(self, value):
        User: TibilletUser = get_user_model()
        user_paiement, created = User.objects.get_or_create(
            email=value, username=value)

        if created:
            user_paiement: HumanUser
            user_paiement.client_source = connection.tenant
            user_paiement.client_achat.add(connection.tenant)
            user_paiement.is_active = False
        else:
            user_paiement.client_achat.add(connection.tenant)

        user_paiement.save()
        return user_paiement.email

    def validate_prices(self, value):
        print(value)

        # on vérifie que chaque article existe et a sa quantité.
        # et qu'il y ai au moins un billet pour la reservation.
        config = Configuration.get_solo()
        self.nbr_ticket = 0
        self.prices_list = []
        for entry in value:
            try:
                price = Price.objects.get(pk=entry['uuid'])
                price_object = {
                    'price': price,
                    'qty': float(entry['qty']),
                }

                if price.product.categorie_article == Product.BILLET:
                    self.nbr_ticket += entry['qty']

                    # Si les noms sont requis pour la billetterie
                    if config.name_required_for_ticket and entry['qty'] > 0:
                        if not entry.get('customers'):
                            raise serializers.ValidationError(_(f'customers non trouvés'))
                        if len(entry.get('customers')) != entry['qty']:
                            raise serializers.ValidationError(_(f'nombre customers non conforme'))

                        price_object['customers'] = entry.get('customers')

                self.prices_list.append(price_object)

            except Price.DoesNotExist as e:
                raise serializers.ValidationError(_(f'price non trouvé : {e}'))
            except ValueError as e:
                raise serializers.ValidationError(_(f'qty doit être un entier ou un flottant : {e}'))

        '''
        products = [
                      {
                        "uuid": "8c419d35-11a1-43b6-b500-b79db665d560",
                        "qty": 2,
                        "customers": [
                          {
                            "first_name": "Jean-Michel",
                            "last_name": "Amoitié"
                          },
                          {
                            "first_name": "Ellen",
                            "last_name": "Ripley"
                          }
                        ]
                      },
                      {
                        "uuid": "c6e847d4-baaa-4d21-a4f0-a572b8319615",
                        "qty": 1,
                        "customers": [
                          {
                            "first_name": "Douglas",
                            "last_name": "Adams"
                          }
                        ]
                      }
                    ]
                    
                products = [
                      {
                        "uuid": "8c419d35-11a1-43b6-b500-b79db665d560",
                        "qty": 2
                      },
                      {
                        "uuid": "c6e847d4-baaa-4d21-a4f0-a572b8319615",
                        "qty": 1
                      }
                    ]
        '''
        return value

    def validate(self, attrs):
        if self.nbr_ticket == 0:
            raise serializers.ValidationError(_(f'pas de billet dans la reservation'))

        config = Configuration.get_solo()
        reservation = Reservation.objects.create(
            user_commande=self.user_commande,
            event=attrs.get('event'),
        )

        lignes_article = []
        for price in self.prices_list:
            ligne_article = LigneArticle.objects.create(
                price=price.get('price'),
                qty=price.get('qty'),
            )
            lignes_article.append(ligne_article)

            if config.name_required_for_ticket and price.get('customers'):
                for customer in price.get('customers'):
                    ticket = Ticket.objects.create(
                        reservation=reservation,
                        first_name=customer.get('first_name'),
                        last_name=customer.get('last_name'),
                    )

        metadata = {'reservation':f'{reservation.uuid}'}
        new_paiement_stripe = creation_paiement_stripe(
            email_paiement=self.user_commande.email,
            liste_ligne_article=lignes_article,
            metadata=metadata,
            source=Paiement_stripe.API_BILLETTERIE,
            reservation=reservation,
            absolute_domain=self.context.get('request').build_absolute_uri().partition('/api')[0],
        )

        if new_paiement_stripe.is_valid():
            paiement_stripe : Paiement_stripe  = new_paiement_stripe.paiement_stripe_db
            paiement_stripe.lignearticle_set.all().update(status=LigneArticle.UNPAID)

            reservation.tickets.all().update(status=Ticket.NOT_ACTIV)

            reservation.paiement = paiement_stripe
            reservation.status = Reservation.UNPAID
            reservation.save()

            print(new_paiement_stripe.checkout_session.stripe_id)
            # return new_paiement_stripe.redirect_to_stripe()
            self.checkout_session = new_paiement_stripe.checkout_session
            return super().validate(attrs)

        else:
            raise serializers.ValidationError(_(f'checkout strip not valid'))

    def to_representation(self, instance):
        representation = super().to_representation(instance)
        logger.info(f"{self.checkout_session.url}")
        representation['checkout_url'] = self.checkout_session.url
        # import ipdb;ipdb.set_trace()
        return representation


