/*
The routines in this file are specific to the IPayV1 and IPayV2 functioanlity.
The * routines are not supported yet.

interface IPayV1:
    function payMintInfo() external view returns (uint256 payAgent, uint256 payWebsite, uint256 delayBlocks, uint256 minMints);
    function payMint(uint256 _AgentId, uint256 _websiteId) external payable returns(uint256 tokenId);
    function payWithdraw() external returns(bool);
    function payWithdrawTitled() external returns(bool);
    *function paySweep(address _anAccount) external returns(bool);
    function payTreasuryBalance() external view returns(uint256 BalanceWei);
    function payAgentBalance(address _account) external view returns(uint256 payBalanceWei, uint256 payDeadline, uint256 payCount);
    function payMintPrice() external view returns(uint256 mintTfuelWei);
    *function payActive() external view returns (bool);

interface IPayV2:
    --function payBurn(uint256 _tokenId) external payable ;
    function payPrice(uint8 _index) external view returns(uint256 tfuelWei);
    *function penniesSet(uint8 _index, uint256 _mintPennies) external;
    *function penniesRead(uint8 _index) external view returns(uint256 pennies);

*/


// arrProjects[_index]['D']['prices']['mintPriceTfuelWei']
// arrProjects[_index]['D']['pennyPriceObj']['priceOfTfuel']
//function calculateCostsNormal(_index) {
function calculateMintNormal(_index) {

    let mintTfuelWei = arrProjects[_index]['D']['prices']['mintPriceTfuelWei'];
    let priceOfTfuel = arrProjects[_index]['D']['pennyPriceObj']['priceOfTfuel'];

    let theMintTfuel = Number(BigInt(mintTfuelWei) / BigInt(10000000000000000)) / 100;
    arrProjects[_index]['D']['prices']['mintPriceTfuel'] = theMintTfuel.toString();

    // write out the mint information here.
    let priOfTfuel = Number(priceOfTfuel);
    //console.log('priOfTfuel: ' + priOfTfuel);

    let thePrice = Number(BigInt(priOfTfuel * Number(mintTfuelWei)) / BigInt(10000000000000000)) / 100;
    const elem = document.getElementById("mintCostId" + _index);
    if (elem != null) {
        elem.innerHTML = "Minting Price: ~$" + thePrice;
        document.getElementById("mintTfuelId" + _index).innerHTML = "Required Coin:  " + theMintTfuel + " tfuel";

        if (arrGlobals['BalanceTfuel'] > Number(arrProjects[_index]['D']['prices']['mintPriceTfuel'])) {
            document.getElementById("mintButtonId" + _index).addEventListener('click', function () { payMint(_index) }, false);
        } else {
            writeDisableTfuel(_index)
        }

        // show mint button - assumes minting is always an option
        //console.log('adding payMint() handler to button');
    }
}
function calculateBurnNormal(_index) {

    let burnTfuelWei = arrProjects[_index]['D']['prices']['burnPriceTfuelWei'];
    let priceOfTfuel = arrProjects[_index]['D']['pennyPriceObj']['priceOfTfuel'];

    let theBurnTfuel = Number(BigInt(burnTfuelWei) / BigInt(10000000000000000)) / 100;
    arrProjects[_index]['D']['prices']['burnPriceTfuel'] = theBurnTfuel.toString();

    // write out the burn information here.
    let priOfTfuel = Number(priceOfTfuel);

    let thePrice = Number(BigInt(priOfTfuel * Number(burnTfuelWei)) / BigInt(10000000000000000)) / 100;
    const elem = document.getElementById("burnCostId" + _index);
    if (elem != null) {
        elem.innerHTML = "Burning Price: ~$" + thePrice;
        document.getElementById("burnTfuelId" + _index).innerHTML = "Required Coin:  " + theBurnTfuel + " tfuel";

        if (arrGlobals['BalanceTfuel'] > Number(arrProjects[_index]['D']['prices']['burnPriceTfuel'])) {
            document.getElementById("burnButtonId" + _index).addEventListener('click', function () { payBurn(_index) }, false);
        } else {
            writeDisableBurn(_index)
        }


        // show burn button - assumes burning is always an option
        //console.log('adding burn() handler to button');
    }
}

//
// This routine requires two items from the smart contract, but can be fetched sequentially.
//
function writeAgentPayInfo(_index) {
    //console.log('writeAgentPayInfo: ' + _index);

    let payObj = arrProjects[_index]['D']['payObj'];
    let agentPayObj = arrProjects[_index]['D']['agentPayObj'];

    // Now display the payout criteria
    let theDays = Number(parseInt((Number(payObj.inactivityDeadline) / Number(arrGlobals['BlocksPerDay']))*100) / 100);
    let theOutput = "Cuts: Agents: " + Number(payObj.payAgentPennies) + " pennies, Websites: " + Number(payObj.payWebsitePennies) + " pennies, min " + Number(payObj.minMintCount) + " sales in " + theDays + " days.";
    //console.log(theOutput);
    document.getElementById("agentCuts" + _index).innerHTML = theOutput;

    let dataItem2 = document.getElementById("agentButtonId" + _index);
    if (dataItem2 != null) {
        if ((BigInt(agentPayObj.payBalanceWei) > BigInt(0)) && (Number(agentPayObj.payCount) >= Number(payObj.minMintCount))) {
            dataItem2.disabled = false;
            dataItem2.addEventListener('click', function () { payWithdraw(_index) }, false);
            //console.log('adding payWithdraw() handler to button');
        } else {
            if (arrGlobals['debugjs']) {
                console.log("INFO: agent conditions not meant for enabling");
            }
        }
    }
    arrProjects[_index]['W']['payMintInfo'] = true;
}

function writeTitledPayInfo(_index) {
    //console.log('writeTitledPayInfo: ' + _index);

    let payObj = arrProjects[_index]['D']['payObj'];
    let titledPayObj = arrProjects[_index]['D']['titledPayObj'];
    //console.log(titledPayObj);
    if (null != titledPayObj) {
        let dataItem = document.getElementById("ownerBalanceId" + _index);
        theBalanceTfuel = Number(BigInt(titledPayObj.payBalanceWei) / BigInt(10000000000000000)) / 100;
        if (dataItem != null) {
            dataItem.innerHTML = "Current Available Balance: " + theBalanceTfuel;
            if (arrGlobals['debugjs']) {
                console.log('INFO: ' + dataItem.innerHTML);
            }

            let dataItem2 = document.getElementById("ownerButtonIPayV1Id" + _index);
            if (null != dataItem2) {
                if (BigInt(titledPayObj.payBalanceWei) > BigInt(0)) {
                    dataItem2.disabled = false;
                    dataItem2.addEventListener('click', function () { payWithdrawTitled(_index) }, false);
                    //console.log('adding payWithdrawTitled() handler to button');
                } else {
                    if (arrGlobals['debugjs']) {
                        console.log("INFO: titled conditions not meant for enabling");
                    }
                }
            }
            arrProjects[_index]['W']['ownerWithdrawIPayV1'] = true;
        }
    } else {
        console.log('ERROR: titledPayObj null');
    }
}

// Note that this routine is called from IPayV1 because there is nothing else we
// need to wait for in order to perform this write.
function writePayAgentBalance(_index) {
    //console.log('writePayAgentBalance: ' + _index);
    let agentPayObj = arrProjects[_index]['D']['agentPayObj'];

    let dataItem = document.getElementById("agentBalance" + _index);
    theBalanceTfuel = Number(BigInt(agentPayObj.payBalanceWei) / BigInt(10000000000000000)) / 100;
    if (dataItem != null) {
        dataItem.innerHTML = "Current Available Balance: " + theBalanceTfuel + " tfuel, Sales count: " + agentPayObj.payCount + ".";
        //console.log(dataItem.innerHTML);

        let dataItemTime = document.getElementById("agentTime" + _index);
        if (dataItemTime != null) {
            dataItemTime.innerHTML = "Deadline Block: " + agentPayObj.payDeadline;
        }
        return true;
    }
    return false;
}

// Special case for admin code is if the owner shows up, we need to fetch the balance of
// the titled
async function PayTitledBalance(_index) {
    console.log('PayTitledBalance: '+_index);
    let titledAddr = arrProjects[_index]['D']['titled'];

    arrProjects[_index]['I']['IPayV1']['Obj'].methods.payAgentBalance(titledAddr).call().then(agentPayObj => {
        //console.log('handling: payAgentBalance()');
        if (null == agentPayObj) {
            console.log('ERROR: Was setting to null');
        }
        arrProjects[_index]['D']['titledPayObj'] = agentPayObj;
        writeTitledPayInfo(_index);
        showPage(_index);
    });
}

async function IPayV1(_index) {
    //
    // If the visitor is registered on this contract, their balance will be in this agentPayObj. 
    // If the visitor is not the titled, PayTitledBalance() should be called to get the balance of the 
    // titled. 
    //
    arrProjects[_index]['I']['IPayV1']['Obj'].methods.payAgentBalance(arrGlobals['visitor']).call().then(agentPayObj => {
        //console.log('handling: payAgentBalance()');
        arrProjects[_index]['D']['agentPayObj'] = agentPayObj;

        if (writePayAgentBalance(_index)) {
            arrProjects[_index]['I']['IPayV1']['Obj'].methods.payMintInfo().call().then(payObj => {
                arrProjects[_index]['D']['payObj'] = payObj;
                writeAgentPayInfo(_index);
                showPage(_index);
            });
        }
    });

    arrProjects[_index]['I']['IPayV1']['Obj'].methods.payMintPrice().call().then(mintTfuelWei => {
        // mintPriceTfuel
        arrProjects[_index]['D']['prices']['mintPriceTfuelWei'] = mintTfuelWei;
        //arrProjects[_index]['D']['mintTfuelWei'] = mintTfuelWei;
        showPage(_index);
    });

    arrProjects[_index]['I']['IPayV1']['Obj'].methods.payTreasuryBalance().call().then(BalanceWei => {
        arrProjects[_index]['D']['payTreasuryBalanceWei'] = BalanceWei;
        showPage(_index);
    });
}

//
// ----------------------------- Handlers -------------------------------------------
//

// the onclick handler for mint.
async function payMint(_index) {
    //console.log("payMint The Index is: " + _index);
    console.log('HANDLER: payMint()');

    if (await IsCorrectNetwork()) {
        // two parameters are agentId and websiteId
        console.log("agentId: " + arrGlobals['agent']);
        console.log("websiteId: " + arrGlobals['website']);
        console.log("Visitor: " + arrGlobals['visitor']);
        let priceWei = arrProjects[_index]['D']['prices']['mintPriceTfuelWei'];
        console.log("calling minter: " + priceWei);

        let dataObj = document.getElementById("mintTrxnId" + _index);
        if (BigInt(arrGlobals['BalanceTfuelWei']) > BigInt(priceWei)) {

            let theBlock = Number(await window.ethereum.request({ method: 'eth_blockNumber' }));
            console.log('theBlock: ' + theBlock);

            let currentGasPrice = await web3.eth.getGasPrice();
            console.log('currentGasPrice: ' + currentGasPrice);
/*
            // NOTE: For testing only.
            // If the project is expecting a mint notification, give it to them here.
            let theHash = '0x12345';
            let cbFunc = null;
            let cbObj = document.getElementById('mintCallbackId');
            if (null != cbObj) {
                cbFunc = cbObj.innerHTML;
                if (null != cbFunc) {
                    console.log('call: ' + cbFunc + '("tfuel")');
                    eval(cbFunc + '("' + theBlock + '","' + theHash + '");');
                }
            } 
*/
            // attempt minting
            document.body.style.cursor = 'wait';
            try {
                //console.log('TODO: Bring wallet call back');

                await arrProjects[_index]['I']['IPayV1']['Obj'].methods.payMint(Number(arrGlobals['agent']), Number(arrGlobals['website'])).send({
                    from: arrGlobals['visitor'],
                    value: priceWei,
                    gasPrice: currentGasPrice
                }).on('error', (error) => {
                    console.log('on handler');
                    console.log(error);
                }).then(tx => {
                    console.log(tx);
                    var transactionRef = '<a href="http://www.thetascan.io/hash/?hash=' + tx.transactionHash + '" target="_blank">Trxn Link & Hash</a>';
                    //console.log(transactionRef);
                    dataObj.innerHTML = transactionRef;

                    // If the project is expecting a mint notification, give it to them here.
                    let cbFunc = null;
                    let cbObj = document.getElementById('mintCallbackId');
                    if (null != cbObj) {
                        cbFunc = cbObj.innerHTML;
                        if (null != cbFunc) {
                            console.log('call: ' + cbFunc + '("tfuel")');
                            eval(cbFunc + '("' + theBlock + '","' + tx.transactionHash + '");');
                        }
                    }
                    // 3 seconds after minting something, reload the page. The holder code will
                    // not see the NFT yet (ThetaScan still have to process the transaction) but
                    // anything gated on owning the NFT can be unlocked.
                    delayRefresh(3000);

                });

            } catch (error) {
                console.log("in error handler");
                console.log(error.message);
                dataObj.innerHTML = error.message;
            }
            document.body.style.cursor = 'default';

        } else {
            // does not hold enough balance to mint
            dataObj.innerHTML = 'Insufficient funds';
            delayHide(3000, "mintTrxnId" + _index);
        }
        dataObj.style.display = "block";
    }
}


// the onclick handler for withdraw.
async function payWithdraw(_index) {
    if (await IsCorrectNetwork()) {
        // two parameters are agentId and websiteId
        console.log("calling payWithdraw(): " + arrGlobals['visitor']);

        let currentGasPrice = await web3.eth.getGasPrice();

        document.body.style.cursor = 'wait';
        let dataObj = document.getElementById("agentTrxnId" + _index);
        try {
            await arrProjects[_index]['I']['IPayV1']['Obj'].methods.payWithdraw().send({
                from: arrGlobals['visitor'],
                gasPrice: currentGasPrice
            }).on('error', (error) => {
                console.log('on handler');
                console.log(error);
            }).then(tx => {
                //console.log(tx);
                var transactionRef = '<a href="http://www.thetascan.io/hash/?hash=' + tx.transactionHash + '" target="_blank">Trxn Link & Hash</a>';
                //console.log(transactionRef);
                dataObj.innerHTML = transactionRef;
            });

        } catch (error) {
            //console.log(error.message);
            dataObj.innerHTML = error.message;
        }
        dataObj.style.display = "block";
        document.body.style.cursor = 'default';
    }
}


//
// This should only be called when the visitor to the website is either the owner or titled.
//
async function payWithdrawTitled(_index) {
    if (await IsCorrectNetwork()) {
        // two parameters are agentId and websiteId
        console.log("calling payWithdrawTitled(): " + arrGlobals['visitor']);

        let currentGasPrice = await web3.eth.getGasPrice();

        document.body.style.cursor = 'wait';
        let dataObj = document.getElementById("ownerTrxnId" + _index);
        try {
            await arrProjects[_index]['I']['IPayV1']['Obj'].methods.payWithdrawTitled().send({
                from: arrGlobals['visitor'],
                gasPrice: currentGasPrice
            }).on('error', (error) => {
                console.log('on handler');
                console.log(error);
            }).then(tx => {
                //console.log(tx);
                var transactionRef = '<a href="http://www.thetascan.io/hash/?hash=' + tx.transactionHash + '" target="_blank">Trxn Link & Hash</a>';
                //console.log(transactionRef);
                dataObj.innerHTML = transactionRef;
            });

        } catch (error) {
            //console.log(error.message);
            dataObj.innerHTML = error.message;
        }
        dataObj.style.display = "block";
        document.body.style.cursor = 'default';
    }
}



/*
arrGlobals['I']['IPayV2']['ABI'].push({ "inputs": [], "name": "BURN_INDEX", "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], "stateMutability": "view", "type": "function" });
arrGlobals['I']['IPayV2']['ABI'].push({ "inputs": [], "name": "MINT_INDEX", "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], "stateMutability": "view", "type": "function" });
arrGlobals['I']['IPayV2']['ABI'].push({ "inputs": [], "name": "RENEW_INDEX", "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], "stateMutability": "view", "type": "function" });
arrGlobals['I']['IPayV2']['ABI'].push({ "inputs": [], "name": "SENDLOCK_INDEX", "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], "stateMutability": "view", "type": "function" });

    function payBurn(uint256 _tokenId) external payable ;
    function payPrice(uint8 _index) external view returns(uint256 tfuelWei);
    function penniesSet(uint8 _index, uint256 _mintPennies) external;
    function penniesRead(uint8 _index) external view returns(uint256 pennies);
*/
//
// Note that penniesRead() takes an index given from each of the above routines.
//
async function IPayV2(_index) {
    //console.log("IPayV2 not implimented yet");

    arrProjects[_index]['I']['IPayV2']['Obj'].methods.BURN_INDEX().call().then(theIndex => {
        //console.log("BURN_INDEX:" + theIndex);
        arrProjects[_index]['I']['IPayV2']['Obj'].methods.payPrice(theIndex).call().then(tfuelWei => {
            console.log("BURN_INDEX: payPrice wei:" + tfuelWei);
            arrProjects[_index]['D']['prices']['burnPriceTfuelWei'] = tfuelWei;
            showPage(_index);
        });
    });
    arrProjects[_index]['I']['IPayV2']['Obj'].methods.MINT_INDEX().call().then(theIndex => {
        //console.log("MINT_INDEX:" + theIndex);
        arrProjects[_index]['I']['IPayV2']['Obj'].methods.payPrice(theIndex).call().then(tfuelWei => {
            console.log("MINT_INDEX: payPrice wei:" + tfuelWei);
            arrProjects[_index]['D']['prices']['mintPriceTfuelWei'] = tfuelWei;
            showPage(_index);
        });
    });
    arrProjects[_index]['I']['IPayV2']['Obj'].methods.RENEW_INDEX().call().then(theIndex => {
        //console.log("RENEW_INDEX:" + theIndex);
        arrProjects[_index]['I']['IPayV2']['Obj'].methods.payPrice(theIndex).call().then(tfuelWei => {
            console.log("RENEW_INDEX: payPrice wei:" + tfuelWei);
            arrProjects[_index]['D']['prices']['renewPriceTfuelWei'] = tfuelWei;
            showPage(_index);
        });
    });
    arrProjects[_index]['I']['IPayV2']['Obj'].methods.SENDLOCK_INDEX().call().then(theIndex => {
        //console.log("SENDLOCK_INDEX:" + theIndex);
        arrProjects[_index]['I']['IPayV2']['Obj'].methods.payPrice(theIndex).call().then(tfuelWei => {
            console.log("SENDLOCK_INDEX: payPrice wei:" + tfuelWei);
            arrProjects[_index]['D']['prices']['sendlockPriceTfuelWei'] = tfuelWei;
            showPage(_index);
        });
    });
}

//
// There are two identical payBurn() routines, one in IPayV2 and the other in IERC721ExV1. When we
// drop into this routine, we need to choose the correct interface (one or the other).
//
// TODO: fix theTokenId(visitorAddr) so that it is exposed in an interface.
//
// In order to payBurn(), we have to provide the token Id. Right now, there are only two 
// ways to get that Id. One is using tokenOf() in the IERC721ExV1M interface and the other
// is theTokenId(visitorAddr) in the ICore interface. 
//
// As it turns out, theTokenId() will only respond successfully if the contract is bSoulBound.
//
async function payBurn(_index) {

    if (await IsCorrectNetwork()) {

        // two parameters are agentId and websiteId
        console.log("calling payBurn(): " + arrGlobals['visitor']);

        let contractObj = arrProjects[_index]['I']['IERC721ExV1']['Obj'];
        if (null == contractObj) {
            contractObj = arrProjects[_index]['I']['IPayV2']['Obj'];
            console.log('using IPayV2 for payBurn()');
        }
        if (null == contractObj) {
            console.log('ERROR: Neither interface provides payBurn()');
            return;
        }

        let theTokenId = 0;
        if (typeof arrProjects[_index]['D']['theTokenId'] !== 'undefined' && arrProjects[_index]['D']['theTokenId'] != 0) {
            theTokenId = arrProjects[_index]['D']['theTokenId'];
        }
        if (0 == theTokenId) {
            console.log('need theTokenId');
            return;
        }

        console.log('burning tokenId: '+theTokenId);
        let burnWei = arrProjects[_index]['D']['prices']['burnPriceTfuelWei'];
        console.log('burnWei: ' + burnWei);

        let currentGasPrice = await web3.eth.getGasPrice();

        document.body.style.cursor = 'wait';
        let dataObj = document.getElementById("burnTrxnId" + _index);
        try {

            await contractObj.methods.payBurn(theTokenId).send({
                from: arrGlobals['visitor'],
                value: burnWei,
                gasPrice: currentGasPrice
            }).on('error', (error) => {
                console.log('on handler');
                console.log(error);
            }).then(tx => {
                //console.log(tx);
                var transactionRef = '<a href="http://www.thetascan.io/hash/?hash=' + tx.transactionHash + '" target="_blank">Trxn Link & Hash</a>';
                //console.log(transactionRef);
                dataObj.innerHTML = transactionRef;
            });

        } catch (error) {
            //console.log(error.message);
            dataObj.innerHTML = error.message;
        }
        dataObj.style.display = "block";
        document.body.style.cursor = 'default';
    }
}
