/*
 * last modified---
 * 	06-10-26 add DOM ids to support browser automation
 * 	10-14-25 prevent errors if Crowdsale isn't deployed yet
 * 	07-18-24 debug, add native units labeling on prices
 * 	07-13-24 new
 *
 * purpose---
 * 	provide UI to purchase $ENSHROUD erc20 tokens from Crowdsale contract
 */

import React, { useState } from 'react';
import useEth from '../EthContext/useEth';
import Table from 'react-bootstrap/Table';
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
import InputGroup from 'react-bootstrap/InputGroup';
const BigNumber = require("bignumber.js");


/* method to render the table of current Tier status
 * @param props.tierNumber the number of the Tier (0-based)
 * @param props.tierTokens the number of tokens remaining for sale in the Tier
 * @param props.tierPrice the number of wei in ETH (native tokens) which a
 * @param props.nativeUnits the units of the native tokens
 * buyer must transfer to purchase a whole $ENSHROUD token
 */
function TierStatus(props) {
	// render table
	const { state: { web3 } } = useEth();
	const hdr = "TierStatusHeader";
	const bdy = "TierStatusBody";
	const dispTier = +props.tierNumber + 1;
	const dispPrice = web3.utils.fromWei(`${props.tierPrice}`);
	const dispTokens = new BigNumber(props.tierTokens).dividedBy("1e18");
	const nextPrice = dispPrice * 2;
	const units = props.nativeUnits;
	return (
		<>
			<h2 align="center">Enshroud Crowdsale</h2>
			<br/>
			<h2>Crowdsale Status</h2>
			<Table striped bordered variant="dark">
				<caption className="caption-top">
					Current Tier Statistics
				</caption>
				<thead>
					<tr align="center" key={hdr}>
						<th scope="col">Tier Number</th>
						<th scope="col">Tokens Remaining</th>
						<th scope="col">Tier Price ({units})</th>
						<th scope="col">Next Tier Price ({units})</th>
					</tr>
				</thead>
				<tbody>
					{ /* add row for data display */ }
					<tr align="center" key={bdy}>
						<td>{dispTier}</td>
						<td>{dispTokens.valueOf()}</td>
						<td>{dispPrice}</td>
						<td>{nextPrice}</td>
					</tr>
				</tbody>
			</Table>
		</>
	);
}

/* method to supply an entry form for a new Enshroud purchase by the user
 * @param props.tierNumber the current tier index
 * @param props.tierSupply the current wei amount of $ENSHROUD remaining in Tier
 * @param props.tierPrice the current tier's price in wei (for a whole token)
 * @param props.userBalance the number of $ENSHROUD tokens user currently owns
 * @param props.nativeUnits the units of the native tokens
 * @param props.updateTotal method to update tier supply after successful buy
 * @param props.updateTier method to update tier number after successful buy
 * @param props.updatePrice method to update tier price after successful buy
 * @param props.updateBalance method to update number of user-owned $ENSHROUD
 */
function EnshroudPurchase(props) {
	// enable use of our contracts and wallet accounts
	const { state: { accounts, contracts, web3 } } = useEth();
	const crowdSaleContract = contracts["Crowdsale"];
	const userAcct = web3.utils.toChecksumAddress(accounts[0]);
	const tierPrice = new BigNumber(props.tierPrice);
	const nxtTierPrice = tierPrice.times(2);
	var tokenSupply = new BigNumber(props.tierSupply);
	const decimals = new BigNumber("1e18");
	var userBalance = new BigNumber(props.userBalance);

	// user's entered purchase amount, in whole tokens (1e-18 scale, string)
	const [purchaseAmt, setPurchaseAmt] = useState(0);

	// number of tokens to buy from current Tier
	var fromThisTierWei = new BigNumber(purchaseAmt).times(decimals);
	// number of tokens to buy from next Tier
	var fromNextTierWei = new BigNumber(0);
	var purchaseWei = new BigNumber(purchaseAmt).times(decimals);
	var nxtTierSupply = new BigNumber("1e6").times(decimals);
	if (purchaseWei.gt(tokenSupply)) {
		// eat up all of current tier, rest from next tier
		fromThisTierWei = tokenSupply;
		fromNextTierWei = purchaseWei.minus(tokenSupply);
		nxtTierSupply = nxtTierSupply.minus(fromNextTierWei);
	}
	else {
		tokenSupply = tokenSupply.minus(fromThisTierWei);
	}

	// compute quantity of native token wei this involves
	var fromThisTier = fromThisTierWei.dividedBy(decimals);
	var fromNextTier = fromNextTierWei.dividedBy(decimals);
	var nativeWei
		= fromThisTier.times(tierPrice).plus(fromNextTier.times(nxtTierPrice));

	// process a buy amount value change
	const handlePurchAmtChange = e => {
		const val = e.target.value;
		if (val === '') {
			setPurchaseAmt("0");
		}
		else if (/^[0-9]*/.test(val) && !isNaN(val)) {
			setPurchaseAmt(val);
		}
	};

	// submit a new purchase to the blockchain
	const submitPurchase = async () => {
		// sanity check form inputs
		if (purchaseAmt <= 0) {
			alert("Illegal purchase amount, \"" + purchaseAmt + "\"");
			return;
		}
		// max of 1M tokens at once
		if (purchaseAmt > 1e6) {
			alert("Max of 1,000,000 tokens in any single purchase");
			return;
		}

		// invoke contract purchase method
		await crowdSaleContract.methods.buyTokens(userAcct)
				.send({ from: userAcct, value: nativeWei })
			.then(receipt => {
				// tell React the sale worked
				userBalance = purchaseWei.plus(userBalance);
				props.updateBalance(userBalance.toFixed());
				if (fromNextTierWei.gt(0)) {
					props.updateTier(+props.tierNumber + 1);
					props.updateTotal(nxtTierSupply.toFixed());
					props.updatePrice(nxtTierPrice.toString());
				}
				else {
					props.updateTotal(tokenSupply.toFixed());
				}
			})
			.catch(err => {
				console.error("Error: code " + err.code + ", " + err.message);
				alert("Error: code " + err.code + ", " + err.message);
			});
	};

	// form to enter new purchase
	const purchaseForm =
		<>
			<br/><br/>
			<h3>Buy $ENSHROUD Tokens from Crowdsale Contract</h3>
			<br/>
			<Form>
				<InputGroup className="mb-3">
					<InputGroup.Text>You currently have:</InputGroup.Text>
					<Form.Control type="text" placeholder="0" readOnly
						value={userBalance.dividedBy(decimals).toFixed()}
					/>
					<InputGroup.Text>$ENSHROUD tokens.</InputGroup.Text>
				</InputGroup>
				<Form.Group className="mb-3">
					<Form.Label>Number of tokens to buy</Form.Label>
					<Form.Control type="text" placeholder="0" id="purchaseAmt"
						value={purchaseAmt} onChange={handlePurchAmtChange}
					/>
				</Form.Group>
				<Form.Group className="mb-3" controlId="cost">
					<Form.Label>
						Cost in native tokens ({props.nativeUnits})
					</Form.Label>
					<Form.Control type="text" placeholder="0" readOnly
						value={nativeWei.dividedBy(decimals).toFixed()}
					/>
				</Form.Group>
				<Button variant="success" className="m-3"
					onClick={() => submitPurchase()} id="submitPurchase"
					title="Complete purchase"
				>
					Buy Tokens
				</Button>
			</Form>
		</>;

	// render mint-by-purchase form
	return (
		<div id="newBuy">
			{ purchaseForm }
		</div>
	);
}

/* show status of current Tier and its sales, and provide a form for buying
 * tokens from the Crowdsale contract
 * @param props.tierNumber the current Tier number (0-based index)
 * @param props.tierTokens the remaining token inventory in the current Tier
 * @param props.tierPrice the number of wei to buy one token in this Tier
 * @param props.userBalance the number of tokens user currently owns
 * @param props.setTier method for setting/changing the Tier
 * @param props.setTokens method for setting/updating the Tier token inventory
 * @param props.setPrice method for setting/updating the Tier token wei price
 * @param props.setUserBal method for setting/updating the user token balance
 */
function EnshroudPurchases(props) {
	// enable use of our contracts and wallet accounts
	const { state: { accounts, contracts, chainConn } } = useEth();
	var startBlock = chainConn.chainConfig.tokenGenesis;
	if (startBlock === undefined) {
		console.error("No tokenGenesis found for CrowdSale on chain Id "
						+ chainConn.chainConfig.chainId);
		startBlock = "earliest";
	}
	const crowdsaleContract = contracts["Crowdsale"];
	const enshTokenContract = contracts["EnshroudToken"];
	const userAcct = accounts[0];
	var tierIndex = props.tierNumber;
	var tierSupply = props.tierTokens;
	var tierPrice = props.tierPrice;
	var userBalance = props.userBalance;
	// find the asset which is native tokens
	var protocolAssets = [].concat(chainConn.chainConfig.assetList);
	var nativeAsset = protocolAssets.find(elt => elt.method === 'native');

	// obtain the current token Tier index (0-based)
	const fetchTierIndex = async () => {
		if (crowdsaleContract === null) return;
		tierIndex = await crowdsaleContract.methods.tierIndex().call(
															{ from: userAcct });
		props.setTier(tierIndex);
	};
	fetchTierIndex();

	// obtain the current Tier's remaining token inventory (in wei)
	const fetchTierSupply = async () => {
		if (crowdsaleContract === null) return;
		tierSupply
			= await crowdsaleContract.methods.tokensInTier(tierIndex).call(
															{ from: userAcct });
		props.setTokens(tierSupply);
	};
	fetchTierSupply();

	// obtain the current Tier's price in wei for a token
	const fetchTierPrice = async () => {
		if (crowdsaleContract === null) return;
		tierPrice = await crowdsaleContract.methods.rates(tierIndex).call(
															{ from: userAcct });
		props.setPrice(tierPrice);
	};
	fetchTierPrice();

	// obtain user's current balance of $ENSHROUD tokens (in wei)
	const fetchUserBalance = async () => {
		userBalance = await enshTokenContract.methods.balanceOf(userAcct).call(
															{ from: userAcct });
		props.setUserBal(userBalance);
	};
	fetchUserBalance();

	// trigger new fetch from Refresh button
	const refreshTier = async () => {
		fetchTierIndex();
		fetchTierSupply();
		fetchTierPrice();
		fetchUserBalance();
	};

	// do actual rendering
	return (
		<div className="enshCrowdsales">
			<TierStatus
				tierNumber={tierIndex}
				tierTokens={tierSupply}
				tierPrice={tierPrice}
				nativeUnits={nativeAsset.symbol}
			/>
			<br/>
			<Button variant="primary" align="center" id="updateTier"
				onClick={() => refreshTier()} className="m-3"
				title="Update Tier status"
			>
				Refresh
			</Button>
			<br/>

			{ /* provide form to enter a new sale */ }
			<EnshroudPurchase
				tierNumber={tierIndex}
				tierSupply={tierSupply}
				tierPrice={tierPrice}
				userBalance={userBalance}
				nativeUnits={nativeAsset.symbol}
				updateTotal={props.setTokens}
				updateTier={props.setTier}
				updatePrice={props.setPrice}
				updateBalance={props.setUserBal}
			/>
			<br/><br/>
		</div>
	);
}

export default EnshroudPurchases;
