from django.http import HttpResponse, JsonResponse
from django.urls import reverse
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.decorators import api_view, permission_classes
from api_partner.serializers import *
from backoffice.models import *
import datetime
from urllib import response
from django.core.paginator import Paginator
from django.http import JsonResponse
from eth_account.messages import defunct_hash_message
from tixsell import settings
from web3 import Web3
from web3.middleware import construct_sign_and_send_raw_middleware
from eth_account import Account
from eth_account.messages import encode_defunct
from eth_account.signers.local import LocalAccount
from django.shortcuts import render, HttpResponse
from mnemonic import Mnemonic
from django.core import signing
import logging
from rest_framework.permissions import IsAuthenticated
from rest_framework import generics, permissions, serializers
from rest_framework import status
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema 
from api.serializers import CategorySerializer
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth import authenticate
import base64
import tempfile
import os
import stripe
import json
from django.core.files.base import ContentFile
from backoffice.forms.signup import SignupForm
from django.utils import timezone
import pytz
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response

class CustomPagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    max_page_size = 100

logger = logging.getLogger('django')


class signup(APIView):
    @swagger_auto_schema(auto_schema=None)
    def get(self, request, format=None):
        form = SignupForm()
        return render(request, 'signup.html', {'form': form})
    
    @swagger_auto_schema(auto_schema=None)
    def post(self, request, format=None):
        try:
            logger.info("try to signup post method")
            logger.info(request.POST)
            email = request.POST.get('username')
            password = request.POST.get('password')
             
            if email and password:
                logger.info("form is valid")
                logger.info("Try to authenticate user")
                user = authenticate(request, username=email, password=password)
                logger.info("User authenticated")
                logger.info(user)
                if user is not None:
                    #check if stripe account already exists
                    seller = Seller.objects.filter(user=user).first()
                    if seller:
                        if seller.stripe_charges_enabled:
                            #account already linked
                            HttpResponseRedirect('https://api.selltix.live/redoc_partner_api/')
                        else:
                            #refresh link
                             
                            refresh_url = 'https://api.selltix.live/partner_api/striperefresh/'+str(user.id)+"/" #request.build_absolute_uri(reverse('stripe-refresh-account-url',kwargs={'uuid': user.id} ))
                            return_url = 'https://api.selltix.live/partner_api/stripereturn/'+str(user.id)+"/" #request.build_absolute_uri(reverse('stripe-return-account-url',kwargs={'uuid': user.id} ))
                        
                            logger.info("Return url %s"%return_url)
                            logger.info("refresh_url url %s"%refresh_url)
                            
                            # on crée le lien de redirection
                            accountLink = stripe.AccountLink.create(
                                account=seller.stripe_user_id,
                                refresh_url=refresh_url,
                                return_url=return_url,
                                type="account_onboarding",
                            )
                            link=accountLink["url"]
                            return HttpResponseRedirect(link)
                    else:
                        seller_profile = Seller()
                        seller_profile.user = user
                        #Create stripe user account
                        account = stripe.Account.create(
                            country=user.country,
                            type="express",
                            capabilities={"card_payments": {"requested": True}, "transfers": {"requested": True}} 
                        )
                        logger.info("===On recoit de stripe ")
                        logger.info(account)
                        seller_profile.stripe_user_id = account["id"]
                        seller_profile.stripe_account_json = json.dumps(account)
                        seller_profile.save()
                        #
                        return_url = 'https://api.selltix.live/partner_api/stripereturn/'+str(user.id)+"/" #request.build_absolute_uri(reverse('stripe-refresh-account-url',kwargs={'uuid': user.id} ))
                        refresh_url = 'https://api.selltix.live/partner_api/striperefresh/'+str(user.id)+"/" #request.build_absolute_uri(reverse('stripe-return-account-url',kwargs={'uuid': user.id} ))
                        logger.info("Return url %s"%return_url)
                        logger.info("refresh_url url %s"%refresh_url)
                        
                        # on crée le lien de redirection
                        accountLink = stripe.AccountLink.create(
                            account=account["id"],
                            refresh_url=refresh_url,
                            return_url=return_url,
                            type="account_onboarding",
                        )
                        logger.info(accountLink)
                        urlToRedirect=accountLink["url"]
                        return HttpResponseRedirect(urlToRedirect)
                else:
                    return HttpResponse(status=401)
            else:
                return HttpResponse(status=500)
        except Exception as e:
            logger.error(e)
            return HttpResponse(status=500)

 

def unpin_image(image):
    try:
        pinata_api_key = settings.PINATA_API_KEY
        # cid is the last parameter of the image url
        cid = image.split("/")[-1]

        # unpinz
        url = "https://api.pinata.cloud/pinning/unpin/"+cid
        headers = {"Authorization": 'Bearer '+pinata_api_key}
        response = requests.delete(url,headers=headers)
        
        return True
    except Exception as e:
        logger.error(e)
        return False

def send_image_to_pinata(image_data, pinata_api_key):
    logger.info("===On envoi à pinata ")
    logger.info(image_data)
    try:
        if isinstance(image_data, str) and ';base64,' in image_data:
            # Handle base64 encoded string
            format, imgstr = image_data.split(';base64,')
            ext = format.split('/')[-1]
            image_data = base64.b64decode(imgstr)
        else:
            # Handle file upload or other formats
            ext = 'jpg'  # Default extension
            if hasattr(image_data, 'name'):
                ext = image_data.name.split('.')[-1]
            if hasattr(image_data, 'read'):
                image_data = image_data.read()
        
        # Create temporary file
       # Create temporary file
        with tempfile.NamedTemporaryFile(suffix=f'.{ext}', delete=False) as temp_file:
            temp_file.write(image_data)
            temp_file_path = temp_file.name
        # Upload image to IPFS
        url = "https://api.pinata.cloud/pinning/pinFileToIPFS"
        headers = {"Authorization": 'Bearer '+pinata_api_key}
       
        # With this
        with open(temp_file_path, 'rb') as file:
            files = {"file": file}
            logger.info("===Envoi a pinata ====")
            response = requests.post(url, files=files, headers=headers)
            logger.info(response.json())
            logger.info(response.status_code)
            # Get the image hash
            ipfs_hash = response.json()["IpfsHash"]
    
        os.unlink(temp_file_path)
        return ipfs_hash
    except Exception as e:
        logger.error(e)
        return None

class register(APIView):
    permission_classes = [IsAuthenticated]

     
    @swagger_auto_schema(
        operation_id='register',
        operation_description="""Register an organizer or update information if already exists.
        <br>On first registration (call), you will need to provide a <b>pin code</b>, that will be used to create your wallet.
        <br>SellTix will manage your wallet transactions in your behalf, and this is required to be able to create tickets on the blockchain.
        <br><br><b>Note:</b>
        <br><br>When registering, or publishing an event, we need to create blockchain transactions. Because these transactions can be slow,
        we have implemented an asynchronous process. We will use the <b>webhookUrl</b> (if provided) to notified you when transaction is done.
        <br><br>To do that, we will send a POST request with a payload in the body of the request:<br>
        <pre>
        <code>
        data = {
            "id": "uuid64",
            "event": "uuid64",
            "type": "string",
            "message": "string"
        }
        </code>
        </pre>
       """,
         tags=['Account information'],
        request_body=UserUpdateSerializer,
        
        responses={
            200: openapi.Response(
                description="Organizer updated successfully",
                schema=openapi.Schema(
                type=openapi.TYPE_OBJECT,
                properties={
                    'id': openapi.Schema(type=openapi.TYPE_INTEGER, description="Organizer ID"),
                    'email': openapi.Schema(type=openapi.TYPE_STRING, description="Organizer's email address"),
                    'first_name': openapi.Schema(type=openapi.TYPE_STRING, description="Organizer's first name"),
                    'last_name': openapi.Schema(type=openapi.TYPE_STRING, description="Organizer's last name"),
                    'date_joined': openapi.Schema(type=openapi.TYPE_STRING, description="Date Organizer joined"),
                    'phoneNumber': openapi.Schema(type=openapi.TYPE_STRING, description="Organizer's phone number"),
                    'walletAddress': openapi.Schema(type=openapi.TYPE_STRING, description="Organizer's wallet address, if created"),
                    'cryptoAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether Organizer accepts crypto payments"),
                    'organizerCompany': openapi.Schema(type=openapi.TYPE_STRING, description="Organizer's company name"),
                    'organizeWebsite': openapi.Schema(type=openapi.TYPE_STRING, description="Organizer's company website"),
                    'webhookUrl': openapi.Schema(type=openapi.TYPE_STRING, description="Organizer's webhook URL"),
                    'maticAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether Organizer accepts MATIC payments"),
                    'usdtAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether Organizer accepts USDT payments"),
                    'usdcAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether Organizer accepts USDC payments"),
                    'cbAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether Organizer accepts CB payments"),
                    'description': openapi.Schema(type=openapi.TYPE_STRING, description="Organizer's description"),
                    'country': openapi.Schema(type=openapi.TYPE_STRING, description="Organizer's country"),
                    'timezone': openapi.Schema(type=openapi.TYPE_STRING, description="Organizer's timezone"),
                }
                ),
                examples={
                    "application/json": {
                            "id": "your_id",
                            "email": "your_email",
                            "first_name": "your_first_name",
                            "last_name": "your_last_name",
                            "date_joined": "2024-07-25T12:40:48.198571",
                            "phoneNumber": "your_phone_number",
                            "walletAddress": "your_wallet_address",
                            "cryptoAccepted": False,
                            "maticAccepted": False,
                            "usdtAccepted": False,
                            "usdcAccepted": False,
                            "cbAccepted": True,
                            "description": "your_description",
                            "organizerContract": "your_contract_address",
                            "organizerCompany": "your_company_name",
                            "organizeWebsite": "your_website",
                            "webhookUrl": "your_webhook_url"
                      
                    }
                }
            ),
            400: openapi.Response(
                description="Bad request",
                schema=openapi.Schema(
                type=openapi.TYPE_OBJECT,
                    properties={
                        'status': openapi.Schema(type=openapi.TYPE_STRING, description="Status of the operation KO"),
                        'reason': openapi.Schema(type=openapi.TYPE_STRING, description="message of the failure exception"),
                    }
                ),
                examples={
                    "application/json": {
                    "Pin code required": {
                        "status": "KO",
                        "reason": "Pin code is required"
                    },
                    "Invalid pin code": {
                        "status": "KO",
                        "reason": "Pin code must be 4 digits"
                    },
                    "Pin code already set":{
                        "status": "KO",
                        'reason':"Pin code can't be changed"
                    },
                    "Any other reason": {
                        "status": "KO",
                        "reason": "the error message"
                    }
                }
                   
                }
            ),
            401: openapi.Response(
                description="Unauthorized",
                examples={
                    "application/json": {
                    
                        "detail": "Given token not valid for any token type",
                        "code": "token_not_valid",
                        "messages": [
                            {
                            "token_class": "AccessToken",
                            "token_type": "access",
                            "message": "Token is invalid or expired"
                            }
                        ]
                      
                }

                }
            ) 
        }
    )
    def patch(self, request, format=None):
        organizer = User.objects.get(id=request.user.id)
        serializer = UserUpdateSerializer(organizer,data=request.data)
        logger.info("===On recoit la requete de mise a jour de l'organisateur===")
        try:
            if serializer.is_valid():
                logger.info(serializer.validated_data)
                if organizer.pinCode and 'pinCode' in serializer.validated_data:
                    jsonToReturn = {
                    "status": "KO",
                    'reason':"Pin code can't be changed"
                    }   
                    return JsonResponse(jsonToReturn, safe=False,status=400)

                serializer.save()
                if organizer.walletAddress is None:
                    #Create wallet 
                    #get pin code from serializer
                    pinCode = serializer.validated_data['pinCode']
                    if pinCode is None:
                        jsonToReturn = {
                            "status": "KO",
                            'reason':'Pin code is required'
                        }
                        return JsonResponse(jsonToReturn, safe=False,status=400)
                    #check pinCode lenght is 4
                    if len(pinCode) !=4 or not pinCode.isdigit():
                        jsonToReturn = {
                            "status": "KO",
                            'reason':'Pin code must be 4 digits'
                        }
                        return JsonResponse(jsonToReturn, safe=False,status=400)
                    #create wallet 
                    mnemo = Mnemonic("english")
                    words = mnemo.generate(strength=256)
                    public_key=None
                    private_key=None
                    try:
                        w3 = Web3(Web3.HTTPProvider(settings.CONTRACT_NODE_URL))
                        account = w3.eth.account.create()
                        private_key = w3.to_hex(account.key)
                        public_key = account.address
                        #update user with encoding keys
                        organizer.generatedWallet=True
                        organizer.walletAddress = public_key
                        organizer.publicKey = public_key
                        #encrypt private key 
                        from api.content import encrypt, decrypt
                        encryptedPrivateKey = encrypt(private_key,pinCode)
                        organizer.privateKey = encryptedPrivateKey
                        organizer.words = encrypt(words,pinCode)
                        # calcule chiffre 
                        theCode = 9999 - int(pinCode)
                        organizer.pinCode = encrypt(str(theCode),os.getenv("SECRET_PIN_KEY"))
                        organizer.save()
                        # Batch create organizer contract
                        task = Tasks()
                        task.status = 0 
                        task.action = "createOrganizerContract"
                        task.metadata =  json.dumps({
                            "refOrganizer": str(organizer.id),
                            "walletAddress": organizer.walletAddress
                        })
                        task.save()
                    except Exception as e:
                        jsonToReturn = {
                        "status": "KO",
                        'reason':str(e)
                        }
                        return JsonResponse(jsonToReturn, safe=False,status=400)
                
                if organizer.organizerContract is None:
                    logger.info("==== Pas de contrat organisateur, on le cree ====")
                    existing_task = Tasks.objects.filter(
                        status=0,
                        action="createOrganizerContract",
                        metadata__contains=str(organizer.id)
                    ).first()

                    if not existing_task:
                        # Batch create organizer contract
                        logger.info("==== Pas de tache en cours, on la cree ====")
                        task = Tasks()
                        task.status = 0
                        task.action = "createOrganizerContract"
                        task.metadata =  json.dumps({
                                "refOrganizer": str(organizer.id),
                                "walletAddress": organizer.walletAddress
                        })
                        task.save()
                
                return Response(UserReadSerializer(organizer).data)
            else:
                jsonToReturn = {
                    "status": "KO",
                    'reason':serializer.errors
                }
                return JsonResponse(jsonToReturn, safe=False,status=400)
        except Exception as e:
            logger.error(e)
            jsonToReturn = {
                    "status": "KO",
                    'reason':str(e)
            }
            return JsonResponse(jsonToReturn, safe=False,status=400)
        


class getCategories(APIView):
    permission_classes = [IsAuthenticated]
    
    @swagger_auto_schema(
    operation_id='getCategories',
    operation_description="Retrieve all categories",
    tags=['Events'],
    responses={
        200: openapi.Response(
            description="List of categories",
            schema=openapi.Schema(
                type=openapi.TYPE_ARRAY,
                items=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'id': openapi.Schema(type=openapi.TYPE_INTEGER, description="Category ID"),
                        'name': openapi.Schema(type=openapi.TYPE_STRING, description="Category name"),
                    }),
                   
            )
            ,examples={
                         "application/json":tuple([
        {
            "id": "3ecd5e86-4984-441a-b4c8-5fd8e1a91baf",
            "name": "Art",
            "createdAt": "2023-09-28T11:22:18.960977",
            "updatedAt": "2023-09-28T11:22:25.056422"
        },
        {
            "id": "fa4e06be-83c7-4225-b969-76df8646f72e",
            "name": "Business",
            "createdAt": "2023-09-28T11:22:45.627135",
            "updatedAt": "2023-09-28T11:22:45.627170"
        },
        {
            "id": "b05db215-150d-47a9-aa90-132fd996d49d",
            "name": "Coaching ou Consultant",
            "createdAt": "2023-09-28T11:23:13.352278",
            "updatedAt": "2023-09-28T11:23:13.352357"
        },
    ])
                    }
        )
    }
    )
    def get(self, request, format=None):
        categories = Category.objects.all()
        serializer = CategorySerializer(categories, many=True)
        return Response(serializer.data)
    
class createEvent(APIView):
    permission_classes = [IsAuthenticated]
     
    @swagger_auto_schema(
        operation_id='createEvent',
        operation_description="""Create an event on SellTix platform.
        <br><br>
        An Event must be associated to a category. So you need first to get all categories with the endpoint <a href="#tag/Events/operation/getCategories"><b>getCategories</b></a>
        and then pass the id of the category you want to associate to the event.
        <br><br>
        You will have 3 possibilities with our Platform:
        <br>
        <ul>
            <li>1. You are managing the streaming of the event yourself. In this case, you need to pass the URL of the event. The URL can be a google meet link, a zoom link, a youtube link or any other link. The URL will be accessible to participants with tickets once the event will start. 
            </li>
            <li>2. We are managing the streaming of the event.</li>
            <li>3. The Event is not live and you want to provide a pre-recorded video. <b><i>Not implemented in the API</i></b></li>
        </ul>
        <br>To manage each option, you need to pass the following parameters:
        <br>
        <ul>
            <li>1. <b>isConference</b>: True if you are managing the streaming of the event yourself. False otherwise.
            </li>
            <li>2. <b>streamWithSelltix</b>: True if we are managing the streaming of the event.  False otherwise.
            </li>
            <li>3. <b>recordedVideo</b>: True if you provide a video file.  False otherwise.
            </li>
        </ul>
        At least once of this parameters must be True.
        <br><br><b>Note:</b>
        Because the image needs to be uploaded on a decentralized server, it can take few seconds before receiving the api response.
        <br><br>
        """,
        #  <br>This solution is less secure since anyone can see the URL once the event has started and sharing it by copying/pasting it.
      
        tags=['Events'],
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
                properties={
                    'refCategory': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_UUID,description="Reference to the event category"),
                    'isConference': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="If true, you are managing the streaming and need to pass the <b>onlineUrl</b> parameter for that url."),
                    'streamWithSelltix': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="If true, ae are managing the streaming for you. isConference and recordedVideo must be set to False"),
                    'recordedVideo': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="<b>Not implemented in our API. Please use our web dashboard.</b>. If true, the event is not live and a video will be played during the event.  isConference and streamWithSellTix must be set to False "),
                    'isPrivate': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="If true, the organizer doesn't want SellTix to promote the event on his platform"),
                    'name': openapi.Schema(type=openapi.TYPE_STRING, description="Event Name"),
                    'description': openapi.Schema(type=openapi.TYPE_STRING, description="Event description"),
                    'eventDate': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_DATETIME, description="Date and time of the event. <b>Very important</b> should be in <strong>UTC format</strong> : %Y-%m-%dT%H:%M:%SZ"),
                    'timezone': openapi.Schema(type=openapi.TYPE_STRING, description="Timezone of the event. default will be Europe/Paris"),
                    'currency': openapi.Schema(type=openapi.TYPE_STRING, description="Currency of the event. default will be EUR"),
                    'duration': openapi.Schema(type=openapi.TYPE_INTEGER, description="Duration of the event"),
                    'onlineUrl': openapi.Schema(type=openapi.TYPE_STRING, description="Conference URL i.e google meet, zoom, youtube, etc."),
                    'website': openapi.Schema(type=openapi.TYPE_STRING, description="Website of the event"),
                    'image': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_BASE64, description="Base64 encoded image data. Example  'image':'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/......'"),
                    'royalty': openapi.Schema(type=openapi.TYPE_INTEGER, description="Royalty you will receive for each sell on marketplace. Please provide a percentage (between 0 and 100)."),
                    # Include other fields here
                    'cryptoAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether crypto payments are accepted"),
                    'cbAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether CB payments are accepted"),
            },
             example={
                   
                        "eventDate": "2024-09-01T10:00:00Z",
                        "image": '',
                        "isPrivate": False,
                        "isConference":True,
                        "streamWithSelltix":False,
                        "recordedVideo":False,
                        "name": "Music conference",
                        "description": "This conference is about music in general",
                        "duration": 120,
                        "onlineUrl": "https://meet.google.com/jnt-qjpd-jni",
                        "website": "https://www.selltix.live",
                        "cryptoAccepted": False,
                        "cbAccepted": True,
                        "createdAt": "2024-07-26T19:07:59.907232",
                        "updatedAt": "2024-07-26T19:07:59.940480",
                        "refCategory": "3ecd5e86-4984-441a-b4c8-5fd8e1a91baf",
                        "timezone":"Europe/Paris",
                        "currency":"EUR",
                        "royalty": 10,
                 
                }
        ),
        
        responses={
            201: openapi.Response(
                description="Event created successfully",
                schema=openapi.Schema(
                type=openapi.TYPE_OBJECT,
                properties={
                   'id': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_UUID, description="Unique identifier for the event"),
                    'refCategory': openapi.Schema(type=openapi.TYPE_STRING,format=openapi.FORMAT_UUID, description="Reference to the event category"),
                    'isConference': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="If true, you are managing the streaming."),
                    'streamWithSelltix': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="If true, ae are managing the streaming for you."),
                    'recordedVideo': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="If true, the event is not live and a video will be played during the event."),
                    'isPrivate': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether the organizer wants SellTix to reference this event"),
                    'name': openapi.Schema(type=openapi.TYPE_STRING, description="Event Name"),
                    'description': openapi.Schema(type=openapi.TYPE_STRING, description="Event description"),
                    'eventDate': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_DATETIME, description="Date and time of the event"),
                    'timezone': openapi.Schema(type=openapi.TYPE_STRING, description="Timezone of the event. ie Europe/Paris"),
                    'currency': openapi.Schema(type=openapi.TYPE_STRING, description="Currency of the event. ie USD, EUR, etc."),
                    'duration': openapi.Schema(type=openapi.TYPE_INTEGER, description="Duration of the event"),
                    'onlineUrl': openapi.Schema(type=openapi.TYPE_STRING, description="Conference URL i.e google meet, zoom, youtube, etc."),
                    'website': openapi.Schema(type=openapi.TYPE_STRING, description="Website of the event"),
                    'image': openapi.Schema(type=openapi.TYPE_STRING, description="Image URL for the event"),
                    'cryptoAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether crypto payments are accepted"),
                    'cbAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether CB payments are accepted"),
                    'sellTixEventPage': openapi.Schema(type=openapi.TYPE_STRING, description="SellTix event page URL where users would be able to purchase tickets"),
                    'royalty': openapi.Schema(type=openapi.TYPE_INTEGER, description="Royalty you will receive for each sell on marketplace. A percentage (between 0 and 100)."),
                 }
                ),
                examples={
                    "application/json": {
                        "id": "461e26f8-9e95-41ce-aa97-755c10e0d67c",
                        "eventDate": "2024-09-01T10:00:00Z",
                        "image": '',
                        "isPrivate": False,
                         "isConference": True,
                        "streamWithSelltix": False,
                        "recordedVideo": False,
                        "name": "Music conference",
                        "description": "This conference is about music in general",
                        "duration": 120,
                        "onlineUrl": "https://meet.google.com/jnt-qjpd-jni",
                        "website": "https://www.selltix.live",
                        "sellTixEventPage": "https://www.selltix.live/event/music-conference",
                        "cryptoAccepted": False,
                        "cbAccepted": True,
                        "createdAt": "2024-07-26T19:07:59.907232",
                        "updatedAt": "2024-07-26T19:07:59.940480",
                        "refCategory": "3ecd5e86-4984-441a-b4c8-5fd8e1a91baf",
                        "timezone":"Europe/Paris",
                        "currency":"EUR",
                        "royalty": 10
                    }
                }
            ),
            400: openapi.Response(
                description="Bad request",
                schema=openapi.Schema(
                type=openapi.TYPE_OBJECT,
                    properties={
                        'status': openapi.Schema(type=openapi.TYPE_STRING, description="Status of the operation KO"),
                        'reason': openapi.Schema(type=openapi.TYPE_STRING, description="message of the failure exception"),
                    }
                ) 
            ),
            401: openapi.Response(
                description="Unauthorized",
                examples={
                    "application/json": {
                    
                        "detail": "Given token not valid for any token type",
                        "code": "token_not_valid",
                        "messages": [
                            {
                            "token_class": "AccessToken",
                            "token_type": "access",
                            "message": "Token is invalid or expired"
                            }
                        ]
                      
                }

                }
            ) 
        }
    )
    def post(self, request, format=None):
       
        try:
            organizer = User.objects.get(id=request.user.id)
            serializer = EventsForCreateCustomSerializer(data=request.data)
            if serializer.is_valid():
                """
                # verify stripe is linked 
                try:
                    if organizer.seller.stripe_charges_enabled==False:
                        jsonToReturn = {
                            "status": "KO",
                            'reason':"Stripe charges are disabled for your account. Please finish your stripe configuration before creating an event"
                        }
                        return JsonResponse(jsonToReturn, safe=False,status=400)
                except:
                    jsonToReturn = {
                        "status": "KO",
                        'reason':"You need to link your stripe account to our platform before creating an event"
                    }
                    return JsonResponse(jsonToReturn, safe=False,status=400)
                """
                # verify event date is in the future
                eventDate = serializer.validated_data.get('eventDate')
                if eventDate < datetime.datetime.now():
                    jsonToReturn = {
                        "status": "KO",
                        'reason':"Event date should be in the future"
                    }
                    return JsonResponse(jsonToReturn, safe=False,status=400)
                #check coherence des données
                isConference = serializer.validated_data.get('isConference')
                streamWithSelltix = serializer.validated_data.get('streamWithSelltix')
                recordedVideo = serializer.validated_data.get('recordedVideo')
                if isConference==False and streamWithSelltix==False and recordedVideo==False:
                    jsonToReturn = {
                        "status": "KO",
                        'reason':"You need to select at least one option for isConference, streamWithSelltix or recordedVideo"
                    }
                    return JsonResponse(jsonToReturn, safe=False,status=400)
                if isConference==True and (streamWithSelltix==True or recordedVideo==True):
                    jsonToReturn = {
                        "status": "KO",
                        'reason':"You can't create a conference and a streamWithSelltix or recordedVideo at the same time"
                    }
                    return JsonResponse(jsonToReturn, safe=False,status=400)
                if streamWithSelltix==True and (recordedVideo==True or isConference==True):
                    jsonToReturn = {
                        "status": "KO",
                        'reason':"You can't create a streamWithSelltix and recordedVideo or isConference at the same time"
                    }
                    return JsonResponse(jsonToReturn, safe=False,status=400)
                if recordedVideo==True and (isConference==True or streamWithSelltix==True):
                    jsonToReturn = {
                        "status": "KO",
                        'reason':"You can't create a isVideoRecorded and isConference or streamWithSelltix at the same time"
                    }
                    return JsonResponse(jsonToReturn, safe=False,status=400)
                
                if recordedVideo:
                    jsonToReturn = {
                        "status": "KO",
                        'reason':"Sorry due to upload video file complexity, not available in our API. Please use our web interface to create your event and upload your video"
                    }
                    return JsonResponse(jsonToReturn, safe=False,status=400)

                # check currency and timezone 
                currency = serializer.validated_data.get('currency')
                timezone = serializer.validated_data.get('timezone')
                if currency:
                    if currency not in settings.CURRENCIES:
                        jsonToReturn = {
                            "status": "KO",
                            'reason':"Currency not supported"
                        }
                        return JsonResponse(jsonToReturn, safe=False,status=400)
                if timezone:
                    if timezone not in pytz.all_timezones:
                        jsonToReturn = {
                            "status": "KO",
                            'reason':"Timezone not supported"
                        }
                        return JsonResponse(jsonToReturn, safe=False,status=400)
                royalty = serializer.validated_data.get('royalty')
                if royalty is None:
                    jsonToReturn = {
                                    "status": "KO",
                                    'reason':"Please provide a royalty"
                    }
                    return JsonResponse(jsonToReturn, safe=False,status=400)
                if royalty<0 or royalty>100:
                    jsonToReturn = {
                                    "status": "KO",
                                    'reason':"Royalty should be between 0 and 100"
                    }
                    return JsonResponse(jsonToReturn, safe=False,status=400)
                else:
                    royalty = royalty*100
               
                # send image to Pinata and save url in the event
                image = serializer.validated_data.get('image')
                if image is not None:
                    pinata_api_key = settings.PINATA_API_KEY
                    image_url = send_image_to_pinata(image, pinata_api_key)
                    if image_url:
                        fullImage = 'https://amber-large-nightingale-955.mypinata.cloud/ipfs/'+image_url
                    else:
                        fullImage = ''
                else:
                    fullImage = ''
                    
                logger.info(serializer.validated_data)
                
                event = serializer.save(refOrganiser=organizer,eventType=0,status=0,venueName='',venueAddress='',venueGeoloc='',
                                        cryptoAccepted=organizer.cryptoAccepted,cbAccepted=organizer.cbAccepted,image=fullImage)
                    
                return JsonResponse(EventsCustomSerializer(event).data, safe=False, status=201)
            else:
                jsonToReturn = {
                    "status": "KO",
                    'reason':serializer.errors
                }
                return JsonResponse(jsonToReturn, safe=False,status=400)
        
        except Exception as e:
            logger.error(e)
            logger.error(serializer.validated_data)
            jsonToReturn = {
                    "status": "KO",
                    'reason':str(e)
            }
            return JsonResponse(jsonToReturn, safe=False,status=400)
    
class updateEvent(APIView):
    permission_classes = [IsAuthenticated]
    @swagger_auto_schema(
        operation_id='updateEvent',
        operation_description="""Update an event.
        <br><br><b>Note:</b>
        Because the image needs to be uploaded on a decentralized server, it can take few seconds before receiving the api response.
        <br><br>
        """,
       
        #  <br>This solution is less secure since anyone can see the URL once the event has started and sharing it by copying/pasting it.
      
        tags=['Events'],
       request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
                properties={
                    'refCategory': openapi.Schema(type=openapi.TYPE_INTEGER, description="Reference to the event category"),
                    'isPrivate': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="If true, the organizer doesn't want SellTix to promote the event on his platform"),
                    'name': openapi.Schema(type=openapi.TYPE_STRING, description="Event Name"),
                    'description': openapi.Schema(type=openapi.TYPE_STRING, description="Event description"),
                    'eventDate': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_DATETIME, description="Date and time of the event. <b>Very important</b> should be in <strong>UTC format</strong> : %Y-%m-%dT%H:%M:%SZ"),
                    'timezone': openapi.Schema(type=openapi.TYPE_STRING, description="Timezone of the event. default will be Europe/Paris"),
                    'currency': openapi.Schema(type=openapi.TYPE_STRING, description="Currency of the event. default will be EUR"),
                    'duration': openapi.Schema(type=openapi.TYPE_INTEGER, description="Duration of the event"),
                    'onlineUrl': openapi.Schema(type=openapi.TYPE_STRING, description="Conference URL i.e google meet, zoom, youtube, etc."),
                    'website': openapi.Schema(type=openapi.TYPE_STRING, description="Website of the event"),
                    'image': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_BASE64, description="Base64 encoded image data. Example  'image':'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/......'"),
                    # Include other fields here
                    'royalty': openapi.Schema(type=openapi.TYPE_INTEGER, description="Royalty you will receive for each sell on marketplace. A percentage (between 0 and 100)."),
                    'cryptoAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether crypto payments are accepted"),
                    'cbAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether CB payments are accepted"),
            },
             example={
                        "eventDate": "2024-12-24T10:00:00Z",
                        "image": '',
                        "isPrivate": False,
                        "name": "Christmas conference",
                        "description": "This conference is about Christmas",
                        "duration": 120,
                        "onlineUrl": "https://meet.google.com/jnt-qjpd-jni",
                        "website": "https://www.selltix.live",
                        "cryptoAccepted": False,
                        "cbAccepted": True,
                        "createdAt": "2024-07-26T19:07:59.907232",
                        "updatedAt": "2024-07-26T19:07:59.940480",
                        "refCategory": "3ecd5e86-4984-441a-b4c8-5fd8e1a91baf",
                        "timezone":"Europe/Paris",
                        "currency":"EUR"
                 
                }
        ),
        
        responses={
            200: openapi.Response(
                description="Event updated successfully",
                schema=openapi.Schema(
                type=openapi.TYPE_OBJECT,
                properties={
                   'id': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_UUID, description="Unique identifier for the event"),
                    'refCategory': openapi.Schema(type=openapi.TYPE_INTEGER, description="Reference to the event category"),
                    'isPrivate': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether the organizer wants SellTix to reference this event"),
                    'name': openapi.Schema(type=openapi.TYPE_STRING, description="Event Name"),
                    'description': openapi.Schema(type=openapi.TYPE_STRING, description="Event description"),
                    'eventDate': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_DATETIME, description="Date and time of the event"),
                    'timezone': openapi.Schema(type=openapi.TYPE_STRING, description="Timezone of the event. ie Europe/Paris"),
                    'currency': openapi.Schema(type=openapi.TYPE_STRING, description="Currency of the event. ie USD, EUR, etc."),
                    'duration': openapi.Schema(type=openapi.TYPE_INTEGER, description="Duration of the event"),
                    'onlineUrl': openapi.Schema(type=openapi.TYPE_STRING, description="Conference URL i.e google meet, zoom, youtube, etc."),
                    'website': openapi.Schema(type=openapi.TYPE_STRING, description="Website of the event"),
                    'image': openapi.Schema(type=openapi.TYPE_STRING, description="Image URL for the event"),
                    'cryptoAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether crypto payments are accepted"),
                    'cbAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether CB payments are accepted"),
                    'isConference': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether the event is a conference"),
                    'royalty': openapi.Schema(type=openapi.TYPE_INTEGER, description="Royalty you will receive for each sell on marketplace. A percentage (between 0 and 100).")
                }
                ),
                examples={
                    "application/json": {
                        "id": "461e26f8-9e95-41ce-aa97-755c10e0d67c",
                         "eventDate": "2024-12-24T10:00:00Z",
                        "image": '',
                        "isPrivate": False,
                        "name": "Christmas conference",
                        "description": "This conference is about Christmas",
                        "duration": 120,
                        "onlineUrl": "https://meet.google.com/jnt-qjpd-jni",
                        "website": "https://www.selltix.live",
                        "cryptoAccepted": False,
                        "cbAccepted": True,
                        "createdAt": "2024-07-26T19:07:59.907232",
                        "updatedAt": "2024-07-26T19:07:59.940480",
                        "refCategory": "3ecd5e86-4984-441a-b4c8-5fd8e1a91baf"
                    }
                }
            ),
            400: openapi.Response(
                description="Bad request",
                schema=openapi.Schema(
                type=openapi.TYPE_OBJECT,
                    properties={
                        'status': openapi.Schema(type=openapi.TYPE_STRING, description="Status of the operation KO"),
                        'reason': openapi.Schema(type=openapi.TYPE_STRING, description="message of the failure exception"),
                    }
                ),
                examples={
                    "application/json": {
                        "status": "KO",
                        "reason": "The reason of the failure"
                    },
                    "Event already published":{
                         "status": "KO",
                        'reason':"Event already published on blockchain. You cannot update it"
                    }
                }
            ),
            401: openapi.Response(
                description="Unauthorized",
                examples={
                    "application/json": {
                    
                        "detail": "Given token not valid for any token type",
                        "code": "token_not_valid",
                        "messages": [
                            {
                            "token_class": "AccessToken",
                            "token_type": "access",
                            "message": "Token is invalid or expired"
                            }
                        ]
                      
                }

                }
            ) 
        }
    )
  
    def patch(self, request, pk=None, format=None):
        try:
            event = Event.objects.get(id=pk, refOrganiser=request.user)
            if event.status>=0:
                jsonToReturn = {
                    "status": "KO",
                    'reason':"Event already published on blockchain. You cannot update it"
                }
                return JsonResponse(jsonToReturn, safe=False,status=400)
            serializer = EventsForCreateCustomSerializer(event, data=request.data, partial=True)
            if serializer.is_valid():
                currency = serializer.validated_data.get('currency')
                timezone = serializer.validated_data.get('timezone')
                if currency:
                    if currency not in settings.CURRENCIES:
                        jsonToReturn = {
                            "status": "KO",
                            'reason':"Currency not supported"
                        }
                        return JsonResponse(jsonToReturn, safe=False,status=400)
                if timezone:
                    if timezone not in pytz.all_timezones:
                        jsonToReturn = {
                            "status": "KO",
                            'reason':"Timezone not supported"
                        }
                        return JsonResponse(jsonToReturn, safe=False,status=400)
                image = serializer.validated_data.get('image')
                if image is not None and len(event.image)>5:
                    unpin_image(event.image)
                    # send new image 
                    pinata_api_key = settings.PINATA_API_KEY
                    image_url = send_image_to_pinata(image, pinata_api_key)
                    if image_url:
                        fullImage = 'https://amber-large-nightingale-955.mypinata.cloud/ipfs/'+image_url
                    else:
                        fullImage = ''
                    serializer.validated_data['image'] = fullImage

                royalty = serializer.validated_data.get('royalty')
                if royalty:
                    if royalty<0 or royalty>100:
                        jsonToReturn = {
                                        "status": "KO",
                                        'reason':"Royalty should be between 0 and 100"
                        }
                        return JsonResponse(jsonToReturn, safe=False,status=400)
                    else:
                        royalty = royalty*100
                updated_event = serializer.save()
                return JsonResponse(EventsCustomSerializer(updated_event).data, safe=False, status=200)
            else:
                return JsonResponse({"status": "KO", 'reason': serializer.errors}, safe=False, status=400)
        except Event.DoesNotExist:
            return JsonResponse({"status": "KO", 'reason': 'Event not found'}, safe=False, status=404)
        except Exception as e:
            logger.error(e)
            return JsonResponse({"status": "KO", 'reason': str(e)}, safe=False, status=400)


class DeleteEvent(APIView):
    permission_classes = [permissions.IsAuthenticated]
    @swagger_auto_schema(
        operation_id='deleteEvent',
        operation_description="""Delete an event.
        <br><br><b>Note:</b> If the event is started the delete operation will not be allowed.
          """,
         tags=['Events'],
         responses={
            200: openapi.Response(
                description="Event deleted successfully"
            ),
            400: openapi.Response(
                description="Bad request",
                schema=openapi.Schema(
                type=openapi.TYPE_OBJECT,
                    properties={
                        'status': openapi.Schema(type=openapi.TYPE_STRING, description="Status of the operation KO"),
                        'reason': openapi.Schema(type=openapi.TYPE_STRING, description="message of the failure exception"),
                    }
                ) 
            ),
            401: openapi.Response(
                description="Unauthorized",
                examples={
                    "application/json": {
                    
                        "detail": "Given token not valid for any token type",
                        "code": "token_not_valid",
                        "messages": [
                            {
                            "token_class": "AccessToken",
                            "token_type": "access",
                            "message": "Token is invalid or expired"
                            }
                        ]
                      
                }

                }
            ) 
        }
    )
    def delete(self, request, pk=None, format=None):
        try:
            event = Event.objects.get(id=pk, refOrganiser=request.user)
            if len(event.image)>5:
                unpin_image(event.image)
            #check event is not started otherwise can't delete
            from backoffice.helpers import hasEventStarted
            
            if hasEventStarted(event):
                return JsonResponse({"status": "KO", 'reason': 'Event is started'}, safe=False, status=400)
            if event.status==1:
                # need to cancel smart contract 
                #TODO batch
                event.status=2
                event.save()
            else:
                event.delete()
            return JsonResponse({},safe=False, status=200)
        except Event.DoesNotExist:
            return JsonResponse({"status": "KO", 'reason': 'Event not found'}, safe=False, status=404)
        except Exception as e:
            return JsonResponse({"status": "KO", 'reason': str(e)}, safe=False, status=400)

class EventAPIListView(APIView):
    permission_classes = [permissions.IsAuthenticated]
    
    @swagger_auto_schema(
        operation_id='getEvents',
        operation_description="""Get all your event.
        """,
         tags=['Events'],
            responses={
            200: openapi.Response(
                description="List of all organizer events",
                schema=openapi.Schema(
                type=openapi.TYPE_OBJECT,
                properties={
                   'id': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_UUID, description="Unique identifier for the event"),
                    'refCategory': openapi.Schema(type=openapi.TYPE_INTEGER, description="Reference to the event category"),
                    'isPrivate': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether the organizer wants SellTix to reference this event"),
                    'name': openapi.Schema(type=openapi.TYPE_STRING, description="Event Name"),
                    'description': openapi.Schema(type=openapi.TYPE_STRING, description="Event description"),
                    'eventDate': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_DATETIME, description="Date and time of the event"),
                    'timezone': openapi.Schema(type=openapi.TYPE_STRING, description="Timezone of the event. ie Europe/Paris"),
                    'currency': openapi.Schema(type=openapi.TYPE_STRING, description="Currency of the event. ie USD, EUR, etc."),
                    'duration': openapi.Schema(type=openapi.TYPE_INTEGER, description="Duration of the event"),
                    'onlineUrl': openapi.Schema(type=openapi.TYPE_STRING, description="Conference URL i.e google meet, zoom, youtube, etc."),
                    'website': openapi.Schema(type=openapi.TYPE_STRING, description="Website of the event"),
                    'image': openapi.Schema(type=openapi.TYPE_STRING, description="Image URL for the event"),
                    'cryptoAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether crypto payments are accepted"),
                    'cbAccepted': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether CB payments are accepted"),
                    'isConference': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Whether the event is a conference"),
                    'sellTixEventPage': openapi.Schema(type=openapi.TYPE_STRING, description="SellTix event page URL where users would be able to purchase tickets"),
                    'createdAt': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_DATETIME, description="Date and time of the event creation"),
                    'updatedAt': openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_DATETIME, description="Date and time of the event update"),
                    }
                ),
                examples={
                    "application/json": {
                            "count": 1,
                            "next": None,
                            "previous": None,
                            "results": [
                                {
                                "id": "ade56c0f-8175-462d-b548-fac938fcab14",
                                "status": 0,
                                "isPrivate": False,
                                "name": "Music conference",
                                "description": "This conference is about music in general",
                                "sellTixEventPage": "https://www.selltix.live/event/music-conference",
                                "eventDate": "2024-09-01T10:00:00",
                                "timezone": "Europe/Paris",
                                "currency": "EUR",
                                "duration": 120,
                                "onlineUrl": "https://meet.google.com/jnt-qjpd-jni",
                                "website": "https://www.selltix.live",
                                "image": "https://amber-large-nightingale-955.mypinata.cloud/ipfs/QmVSGSQjrprqiNcY9oNk3ac273o2C8uwYfqv6L3PQmKYGK",
                                "cryptoAccepted": False,
                                "cbAccepted": True,
                                "createdAt": "2024-07-27T19:35:08.973445",
                                "updatedAt": "2024-07-27T19:35:08.973457",
                                "refCategory": "3ecd5e86-4984-441a-b4c8-5fd8e1a91baf"
                                }
                            ]
                    }
                }
            ),
            400: openapi.Response(
                description="Bad request",
                schema=openapi.Schema(
                type=openapi.TYPE_OBJECT,
                    properties={
                        'status': openapi.Schema(type=openapi.TYPE_STRING, description="Status of the operation KO"),
                        'reason': openapi.Schema(type=openapi.TYPE_STRING, description="message of the failure exception"),
                    }
                ) 
            ),
            401: openapi.Response(
                description="Unauthorized",
                examples={
                    "application/json": {
                    
                        "detail": "Given token not valid for any token type",
                        "code": "token_not_valid",
                        "messages": [
                            {
                            "token_class": "AccessToken",
                            "token_type": "access",
                            "message": "Token is invalid or expired"
                            }
                        ]
                      
                }

                }
            ) 
        }
    )      
    def get(self, request, format=None):
            try:
                events = Event.objects.filter(refOrganiser=request.user)
                paginator = CustomPagination()
                paginated_events = paginator.paginate_queryset(events, request)
                serializer = EventsForGetSerializer(paginated_events, many=True)
                return paginator.get_paginated_response(serializer.data)
            except Exception as e:
                logger.error(e)
                return JsonResponse({"status": "KO", 'reason': str(e)}, safe=False, status=400)
    
 
class publishEvent(APIView):
    permission_classes = [permissions.IsAuthenticated]
    @swagger_auto_schema(
        operation_id='publishEvent',
        operation_description="""Publish an event.
        <br><br><b>Note:</b> Because this operation is asynchronous due to blockchain, it will return an Http 200 OK response and you will be notify 
        on your webhook url (if you provided one while registering) once the publication done.
        """,
     tags=['Events'],
         responses={
            200: openapi.Response(
                description="Event published successfully",
                examples={
                    "application/json": {
                        "status": "OK",
                        "message": "Publication asked"
                    }
                }
            ),
            400: openapi.Response(
                description="Bad request",
                schema=openapi.Schema(
                type=openapi.TYPE_OBJECT,
                    properties={
                        'status': openapi.Schema(type=openapi.TYPE_STRING, description="Status of the operation KO"),
                        'reason': openapi.Schema(type=openapi.TYPE_STRING, description="message of the failure exception"),
                    }
                ),
                examples={
                   "application/json": {
                        "status": "KO",
                        "reason": "The reason of the failure"
                    },
                     "Event not found": {
                                "status": "KO",
                                "reason": "Event not found"
                        },
                    "Event already published": {
                            "status": "KO",
                            'reason': 'Event already published'
                    },
                    "Organizer contract not found": {
                                "status": "KO",
                                "reason": "Organizer contract not found. Please contact selltix"
                    },
                    "No Tickets": {
                         "status": "KO",
                        "reason": "No Tickets found"
                    }
                }
            ),
            401: openapi.Response(
                description="Unauthorized",
                examples={
                    "application/json": {

                        "detail": "Given token not valid for any token type",
                        "code": "token_not_valid",
                        "messages": [
                            {
                            "token_class": "AccessToken",
                            "token_type": "access",
                            "message": "Token is invalid or expired"
                            }
                        ]

                    }
                }
            )
         }
    )
    def post(self, request, pk=None, format=None):
        try:
            logger.info("publishEvent")
            event = Event.objects.get(id=pk, refOrganiser=request.user)
            if event.refOrganiser.organizerContract is None:
                return JsonResponse({"status": "KO", 'reason': 'Organizer contract not found. Please contact selltix'}, safe=False, status=404)
            if event.status==1:
                return JsonResponse({"status": "KO", 'reason': 'Event already published'}, safe=False, status=404)
            
            # To publish an event a tickettype needs to exists
            nbTickets = TicketType.objects.filter(refEvent=event).count()
            if nbTickets == 0:
                return JsonResponse({"status": "KO", 'reason': 'No Tickets found'}, safe=False, status=404)
            # publish on blockchain
            existing_task = Tasks.objects.filter(
                        status=0,
                        action="deployEventContract",
                        metadata__contains=str(event.id)
                    ).first()

            if not existing_task:
                logger.info("publishEvent: Creating new task")
                task = Tasks()
                task.status = 0
                task.action = "deployEventContract"
                task.metadata =  json.dumps({
                    "refEvent":str(event.id),
                    "refOrganiser":str(request.user.id),
                })
                task.save()
            return JsonResponse({"status": "OK","message":"Publication asked"}, safe=False, status=200)
        except Event.DoesNotExist:
            return JsonResponse({"status": "KO", 'reason': 'Event not found'}, safe=False, status=404)

class stripereturn(APIView):
    @swagger_auto_schema(auto_schema=None)
    def get(self, request, pk=None, format=None):
        try:
                merchantAccount = Seller.objects.get(user__id=pk)
                account = stripe.Account.retrieve(merchantAccount.stripe_user_id)
                logger.info("===On recoit de stripe ")
                logger.info(account)
                #Update stripe json received 
                merchantAccount.stripe_account_json = json.dumps(account)
                
                if account["details_submitted"] and account["charges_enabled"]:
                    merchantAccount.stripe_charges_enabled=True
                merchantAccount.save()
                if merchantAccount.stripe_charges_enabled:
                    return HttpResponseRedirect('https://api.selltix.live/redoc_partner_api/')
                else:
                   # redirecte to striperefresh 
                   refresh_url = 'https://api.selltix.live/partner_api/striperefresh/'+pk+"/" #request.build_absolute_uri(reverse('stripe-return-account-url',kwargs={'uuid': user.id} ))
                   return HttpResponseRedirect(refresh_url)
        except Exception as e:
            logger.error(e)
            return HttpResponse(status=500)
    

class striperefresh(APIView):
    @swagger_auto_schema(auto_schema=None)
    def get(self, request, pk=None, format=None):
        #refresh link
        seller_profile = Seller.objects.get(user__id=pk)
        return_url = 'https://api.selltix.live/partner_api/stripereturn/'+pk+"/" #request.build_absolute_uri(reverse('stripe-refresh-account-url',kwargs={'uuid': user.id} ))
        refresh_url = 'https://api.selltix.live/partner_api/striperefresh/'+pk+"/" #request.build_absolute_uri(reverse('stripe-return-account-url',kwargs={'uuid': user.id} ))
                        
        # on crée le lien de redirection
        accountLink = stripe.AccountLink.create(
                                account=seller_profile.stripe_user_id,
                                refresh_url=refresh_url,
                                return_url=return_url,
                                type="account_onboarding",
        )
        link=accountLink["url"]
        return HttpResponseRedirect(link)