# coding: utf8
from __future__ import unicode_literals
import logging
from backoffice.models import *
from web3 import Web3
from web3.middleware import geth_poa_middleware
from tixsell import settings
from tixsell.settings import TICKET_ABI
from django.db import transaction
logger = logging.getLogger('django')


def getTransactionAndCreateTicket(contract,transactionHash,resultTx,theUser,ticketType):
    #check transaction  and create tickets 
    try:
        logs = resultTx["logs"]
        for log in logs:
            topics = log["topics"]
            logger.info("===============")
            logger.info(topics)
            if len(topics)==4:
                logger.info("==Topics")
                dest = topics[2]
                token=topics[3]
                finalDest="0x"+Web3.to_hex(dest)[-40:]
                logger.info("Token ",token)
                logger.info("===compare %s avec %s"%(finalDest.lower(),theUser.walletAddress.lower()))
                if finalDest.lower()==theUser.walletAddress.lower():
                    logger.info("=== TROUVE TICKET A CREER")
                    logger.info("token %d"%Web3.to_int(token))
                    logger.info("envoi  a ",finalDest)
                    newTicket = Ticket()
                    newTicket.refUser = theUser
                    newTicket.ticketId = Web3.to_int(token)
                    newTicket.refTicketType = ticketType
                    newTicket.lastOwner = theUser.walletAddress
                    newTicket.transactionHash = transactionHash
                    #Info on blockchain... used contract to get tokenInfo 
                    ticketBlockchain = contract.functions.tickets(Web3.to_int(token)).call()
                    logger.info("Ticket lu")
                    logger.info(ticketBlockchain)
                    hashedTicket = ticketBlockchain[3] 
                    result = bytearray(hashedTicket)  # for testing
                    hxstr = "".join(["{:02x}".format(v) for v in result])
                    finalTicketCode="0x"+hxstr
                    pricePaid = ticketBlockchain[4]
                    #convert to human format 
                    finalPrice = Web3.from_wei(pricePaid,'ether')
                    newTicket.hashedTicket = finalTicketCode
                    newTicket.pricePaid = finalPrice
                    newTicket.status = 1
                    newTicket.save()
        return "DONE"
    except Exception as e:
        logger.info(e)
        from backoffice.helpers import sendEmail
        message="Le creation du billet mint du ticket transactionHash<b>%s</b> pour utilisateur %s a échoué !"%(transactionHash,theUser.email)
        message+=str(e)
        sendEmail("csurbier@idevotion.fr","[SellTix] Ticket miné mais creation backend failed",message)
        return "DONE"

def run():
    
        from django.db import transaction
        ticketsToMint = TicketToMint.objects.filter(status=0,nbFailure__lt=3).order_by("createdAt")[:4].select_related("refUser").select_related("refTicketType").select_related("refPayment")
        with transaction.atomic():
            print("===On a ticketsTomint")
            print(ticketsToMint)
            #Limit 4 tickets
            TicketToMint.objects.select_for_update().filter(pk__in=ticketsToMint).update(status=3)

            for ticketMinted in ticketsToMint:
                try:
                    print("mint ticket")
                    print(ticketMinted)
                    if ticketMinted.nbFailure>=3:
                        # warn SELLTIX
                        from backoffice.helpers import sendEmail
                        message="Le mint du ticket <b>%s</b> a échoué !"%ticketMinted.id
                        sendEmail("csurbier@idevotion.fr","[SellTix] TicketToMint failed",message)
                        return
                     
                    theUser = User.objects.get(id=ticketMinted.refUser.id)
                    web3 = Web3(Web3.HTTPProvider(settings.CONTRACT_NODE_URL))
                    DEBUG = os.getenv("DEBUG")
                    if DEBUG:
                        web3.middleware_onion.inject(geth_poa_middleware, layer=0)
                    
                    # Initialize the address calling the fOunctions/signing transactions
                    # Initialize contract ABI and address
                    checkedWalletAddress = web3.to_checksum_address(settings.SELLTIX_WALLET) 
                    # Create smart contract instance
                    checkedTicketAddress = web3.to_checksum_address(ticketMinted.refTicketType.refEvent.ticketContract)
                    contract = web3.eth.contract(address=checkedTicketAddress, abi=TICKET_ABI)
                    # : call 
                    nonce = web3.eth.get_transaction_count(checkedWalletAddress)
                    print("Mint avec nonce")
                    print(nonce)
                    print(ticketMinted.reservationId)
                    print(theUser.walletAddress)
                    transaction = contract.functions.mintTicket(ticketMinted.reservationId,theUser.walletAddress).build_transaction({
                        'from': checkedWalletAddress,
                        'nonce': nonce,
                        'gasPrice': web3.to_wei('30', 'gwei'),
                        'gas': '0'
                    })

                    gas = web3.eth.estimate_gas(transaction)
                    transaction.update({'gas': gas})
                    # peut y'avoir plusieurs tickets ...
                    private_key = settings.SELLTIX_PRIVATE_KEY
                    print("signe and send")
                    signed_txn = web3.eth.account.sign_transaction(transaction, private_key=private_key)
                    receipt = web3.eth.send_raw_transaction(signed_txn.rawTransaction)
                    print("waiting")
                    # blocking: Wait for the transaction to be mined, and get the transaction receipt
                    # blocking: Wait for the transaction to be mined, and get the transaction receipt
                    resultTx = web3.eth.wait_for_transaction_receipt(receipt, timeout=300)
                    print('receipt with confirmed trx hash (after trx executed)')
                    print(resultTx)
                    
                    status = resultTx["status"]
                    if status==1:
                        result = getTransactionAndCreateTicket(contract,web3.to_hex(receipt),resultTx,theUser,ticketMinted.refTicketType)
                        ticketMinted.status=1
                        ticketMinted.save()
                    else:
                        ticketMinted.transactionHash = web3.to_hex(receipt)
                        ticketMinted.status=0
                        ticketMinted.nbFailure+=1
                        ticketMinted.save()
                        
                except Exception as e:
                    ticketMinted.nbFailure+=1
                    ticketMinted.status=0
                    ticketMinted.save()
                    print(e)
