/*
 * last modified---
 * 	08-17-26 add text indicating paid API key required to see relevant events
 * 	10-14-25 don't fail if contracts["Crowdsale"] == null
 * 	10-10-24 use LoadingButton
 * 	03-06-24 permit clearing of address entry field; use BigNumber on totals
 * 	07-18-23 use chainConn from useEth() state
 * 	07-14-23 display totalSupply at end of table
 * 	07-10-23 new
 *
 * purpose---
 * 	provide UI to examine past admin mintages of $ENSHROUD erc20 tokens, and
 * 	to conduct new ones
 */

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 LoadingButton from '../LoadingButton.jsx';
const BigNumber = require("bignumber.js");


// tell the user if they're not entitled to do minting
function NoticeNotMinter() {
	return (
		<>
			<br/><br/>
			<h3>Enter new $ENSHROUD mintage specification:</h3>
			<br/>
			<p>
				⚠️ Cannot find your selected address listed as a minter in
				the <span className="code">EnshroudToken</span> contract.
				Minting disabled.
			</p>
		</>
	);
}

/* render a mintage as a table row
 * @param props.mintage the mintage record retrieved from the on-chain event
 */
function EnshroudMintRenderer(props) {
	const mintage = props.mintage;

	const { state: { contracts } } = useEth();
	const crowdSaleContract = contracts["Crowdsale"];
	// see if our input is equal to Crowdsale address
	var mintRecipient = mintage.recipient;
	if (crowdSaleContract !== null 
		&& mintRecipient === crowdSaleContract.options.address)
	{
		// indicate mintage was to crowdsale contract
		mintRecipient += " (Crowdsale Tier)";
	}

	// render object
	return (
		<tr align="center" valign="middle">
			<td>{mintage.minter}</td>
			<td>{mintRecipient}</td>
			<td>{mintage.amount}</td>
			<td>{mintage.block}</td>
		</tr>
	);
}

/* method to render the table of existing mint records
 * @param props.mintings the list of previous mintage records from events
 * @param props.totalSupply the sum of all previous mintages
 */
function EnshMintsTable(props) {
	let mIdx = 1;
	const nf = new Intl.NumberFormat("en-US", {minimumIntegerDigits: 3});
	const hdr = "header" + nf.format(mIdx);

	// render table
	return (
		<Table striped bordered hover responsive variant="dark">
			<caption className="caption-top">
				Previous ENSHROUD mintings:
			</caption>
			<thead>
				<tr align="center" key={hdr}>
					<th scope="col">Minter</th>
					<th scope="col">Recipient</th>
					<th scope="col">Amount</th>
					<th scope="col">Block</th>
				</tr>
			</thead>
			<tbody>
				{props.mintings.map((minting) =>
					<EnshroudMintRenderer key={mIdx++}
						mintage={minting}
					/>
				)}
				{ /* add row for total mint supply */ }
				<tr align="center" key={mIdx}>
					<td colSpan="2">&nbsp;</td>
					<td>Total Supply:</td>
					<td>{props.totalSupply}</td>
				</tr>
			</tbody>
		</Table>
	);
}

/* method to supply an entry form for an entirely new Enshroud mintage
 * @param props.addMintRecord method to add a single new mint record on success
 * @param props.updateTotal method to update total mintage after successful mint
 * @param props.totalSupply the current total amount of ENSHROUD circulating
 * @param props.authMint true if user has (admin) permission to perform minting
 */
function NewEnshMinting(props) {
	// enable use of our contracts and wallet accounts
	const { state: { accounts, contracts, web3 } } = useEth();
	const enshTokenContract = contracts["EnshroudToken"];

	// track state of form fields
	const [mintForm, setMintForm] = useState({
		recipient: '',
		amount: 50000,
	});

	// process a mint amount value change
	const handleMintAmtChange = e => {
		if (/^[0-9]*/.test(e.target.value)) {
			setMintForm({...mintForm, amount: e.target.value});
		}
	};

	// process a mint recipient address value change
	const handleMintAddressChange = e => {
		if (e.target.value === '' || /^0x[0-9a-fA-F]+/.test(e.target.value)) {
			setMintForm({...mintForm, recipient: e.target.value});
		}
	};

	// submit a new mintage to the blockchain
	const submitMintRecord = async (resolve, reject) => {
		// sanity check form inputs
		if (mintForm.amount <= 0) {
			let badAmt = new Error("Illegal mint amount, \""
									+ mintForm.amount + "\"");
			alert(badAmt.message);
			reject(badAmt);
			return false;
		}
		if (!web3.utils.isAddress(mintForm.recipient)) {
			let badAddr = new Error("Illegal mint recipient address, \""
									+ mintForm.recipient + "\"");
			alert(badAddr.message);
			reject(badAddr);
			return false;
		}

		// scale amount up to 1e18
		const amt = web3.utils.toWei(`${mintForm.amount}`);

		// build new record from form
		const minting = {
			minter: accounts[0],
			recipient: mintForm.recipient,
			amount: mintForm.amount,
			block: 0,
		};

		// invoke contract mint method (must be admin isMinter())
		await enshTokenContract.methods.mint(minting.recipient, amt)
				.send({ from: accounts[0] })
			.then(receipt => {
				// tell React the mint worked
				minting.block = receipt.blockNumber;
				props.addMintRecord(minting);

				// now update the total and inform React
				let existTotal = new BigNumber(props.totalSupply);
				let newTotal = existTotal.plus(minting.amount);
				props.updateTotal(newTotal.toNumber());
			})
			.catch(err => {
				console.error("Error: code " + err.code + ", " + err.message);
				alert("Error: code " + err.code + ", " + err.message);
				reject(err);
				return false;
			});
			resolve(true);
	};

	// form to enter new mintage
	const mintingForm =
		<>
			<br/><br/>
			<h3>Enter new $ENSHROUD mintage specification:</h3>
			<br/>
			<Form>
				<Form.Group className="mb-3" controlId="recipient">
					<Form.Label>Recipient address</Form.Label>
					<Form.Control type="text" placeholder="0x"
						value={mintForm.recipient}
						onChange={handleMintAddressChange}
					/>
				</Form.Group>
				<Form.Group className="mb-3" controlId="amount">
					<Form.Label>Number of tokens (1e-18 scale)</Form.Label>
					<Form.Control type="text" placeholder="50000"
						value={mintForm.amount}
						onChange={handleMintAmtChange}
					/>
				</Form.Group>
				<LoadingButton variant="success"
					buttonStyle="m-3"
					buttonText="Mint Tokens"
					buttonTitle="mint the quantity of tokens to the address"
					buttonIcon="images/plus-circle.svg"
					netMethod={(resolve, reject) => submitMintRecord(resolve, reject)}
				/>
			</Form>
		</>;

	// render new mint form
	return (
		<div id="newMint">
		{
			!props.authMint ? <NoticeNotMinter /> : mintingForm
		}
		</div>
	);
}

/* display past ENSHROUD minting records, and provide opportunity for entry of
 * a new record (shown only if current account has minting privileges)
 * @param props.mintings list of previous mintings
 * @param props.addMintRecord method to record a single new mintage (done here)
 * @param props.addMintRecords method to record downloaded minting events
 * @param props.setMintAuth method to record whether user has minting privs
 * @param props.isMintAuth whether user has minting privileges
 * @param props.totalSupply total amount minted (note no burns possible)
 * @param props.updateTotal method to record new total after mintage
 */
function DoEnshroudMints(props) {
	const mintings = props.mintings;

	// enable use of our contracts and wallet accounts
	const { state: { accounts, contracts, web3, chainConn } } = useEth();
	var startBlock = chainConn.chainConfig.tokenGenesis;
	if (startBlock === undefined) {
		console.error("No tokenGenesis found for EnshroudToken on chain Id "
						+ chainConn.chainConfig.chainId);
		startBlock = "earliest";
	}
	const enshTokenContract = contracts["EnshroudToken"];

	// determine whether this user (accounts[0]) is allowed to mint
	const authToMint = async () => {
		const auth = await enshTokenContract.methods.getMinterStatus(
									accounts[0]).call({ from: accounts[0] });
		props.setMintAuth(auth);
	};
	authToMint();

	// obtain the current total token supply circulating
	const fetchTotalSupply = async () => {
		const circ = await enshTokenContract.methods.totalSupply().call(
														{ from: accounts[0] });
		const tokens = circ / 1e18;
		props.updateTotal(tokens);
	};
	fetchTotalSupply();

	// obtain the set of all previous mintings
	const fetchPastMints = async () => {
		const eventSig = web3.eth.abi.encodeEventSignature(
											'TokensMinted(address,uint256)');
		var prevMintings = [];
		web3.eth.getPastLogs({
			address: enshTokenContract.options.address,
			fromBlock: startBlock,
			topics: [ eventSig ],
		})
		.then(logEventList => {
			logEventList.forEach(logEvent => {
				/* the .data field will contain 130 characters, consisting of
				 * a leading 0x followed by the zero-padded recipient address,
				 * followed by the amount in hex (all concatenated together as
				 * a string)
				 */
				const mintRecipient = logEvent.data.substring(26, 66);
				const hexAmount = logEvent.data.substring(66);
				// convert amount from hex to uint256 in decimal
				var amt = new BigNumber(hexAmount, 16);
				// scale down by 1e18
				amt = amt.dividedToIntegerBy("1e18");
				const prevMint = {
					minter: '(admin)',
					recipient: web3.utils.toChecksumAddress(mintRecipient),
					amount: amt.toNumber(),
					block: logEvent.blockNumber,
				};
				prevMintings.push(prevMint);
			});

			// tell React the fetches worked
			props.addMintRecords(prevMintings);
		})
		.catch(err => {
			alert("Error: code " + err.code + ", " + err.message
				+ "; [you may need a paid API key to see events this old]");
		});
	};

	// do actual rendering
	return (
		<div className="enshMintings">
			<h4>Use button to populate table with previous mintings</h4>
			<p><i>
				Note: due to the age of these events, you may need a JSON-RPC
				endpoint using a paid API key in order to retrieve them.
			</i></p>
			<Button variant="primary"
				onClick={() => fetchPastMints()} className="m-3"
				title="Fetch ENSHROUD minting records from blockchain"
			>
				Fetch Previous Mints
			</Button>
			<br/><br/>

			{ /* display prior mintages in table form */ }
			<EnshMintsTable mintings={mintings}
				totalSupply={props.totalSupply}
			/>

			{ /* provide form to enter a new mintage */ }
			<NewEnshMinting addMintRecord={props.addMintRecord}
				authMint={props.isMintAuth}
				totalSupply={props.totalSupply}
				updateTotal={props.updateTotal}
			/>
			<br/><br/>
		</div>
	);
}

export default DoEnshroudMints;
