/*
 * last modified---
 * 	03-18-25 add ChainAsset.priceFeed
 * 	12-07-23 read ChainAsset templates from file chainConfigs.js
 * 	09-09-23 add ChainAsset.wrapsTo
 * 	08-04-23 add defaultDepFee and defaultWithFee to ChainConfig
 * 	08-02-23 add depositFee and withdrawFee to ChainAsset
 * 	07-25-23 add ChainAsset.method
 * 	07-18-23 add ChainConfig and ChainAsset classes
 * 	07-11-23 add protocolGenesis, tokenGenesis
 * 	05-30-23 add MVOConf
 *
 * purpose---
 * 	class to encapsultate a connection to the current blockchain
 */

import MVOs from './MVOs.js';
import chainConfigs from './chainConfigs.js';


// class to store a config for a supportable token (ERC20, ERC777, or ERC4626)
class ChainAsset {
	constructor() {
		// contract address
		this.contractAddress = '';

		// token name (contract's symbol constant)
		this.symbol = '';

		// user's (account[0]) balance in this token (in wei)
		this.balanceOf = 0n;

		/* deposit type: native (use depositEth), tokens (use depositTokens),
		 * or permit (use depositTokensWithPermit)
		 */
		this.method = 'tokens';

		// custom deposit fee for this token, if any (in %)
		this.depositFee = 0.0;

		// custom withdrawal fee for this token, if any (in %)
		this.withdrawFee = 0.0;

		// optional: contractAddress of another ChainAsset which wraps this one
		this.wrapsTo = '';

		// optional: price feed if we know of one at chain.link
		this.priceFeed = '';
	}

	/* configure a record
	 * @param asset the record to store
	 */
	config(asset) {
		this.contractAddress = asset.contractAddress;
		this.symbol = asset.symbol;
		this.balanceOf = asset.balanceOf;
		this.method = asset.method;
		if (asset.priceFeed !== undefined) this.priceFeed = asset.priceFeed;
	}

	/* update the balance
	 * @param bal current balanceOf() value for user account (BigInt or string)
	 */
	setBalance(bal) {
		if (bal >= 0) {
			this.balanceOf = bal;
		}
	}
}

// class to store the configuration for a supported blockchain
class ChainConfig {
	constructor() {
		// chain Id
		this.chainId = 0;

		// textual name of chain
		this.chain = '';

		// URL for JSON-RPC ABI
		this.jsonrpcURL = 'ws://localhost:8545';

		// URL for etherscan or equivalent
		this.scanURL = '';

		// block number at which the EnshroudProtocol contract was deployed
		this.protocolGenesis = 0;

		// block number at which the EnshroudToken contract was deployed
		this.tokenGenesis = 0;

		// list of erc20/erc777/erc4626 tokens offered here (ChainAssetS)
		this.assetList = [];

		// default deposit fee assessed by the smart contract
		this.defaultDepFee = 0.3;

		// default withdrawal fee assessed by the smart contract
		this.defaultWithFee = 0.3;
	}

	/* configure a record
	 * @param record the record to store (a ChainConfig)
	 */
	config(record) {
		this.chainId = record.chainId;
		this.chain = record.chain;
		this.jsonrpcURL = record.jsonrpcURL;
		this.scanURL = record.scanURL;
		this.protocolGenesis = record.protocolGenesis;
		this.tokenGenesis = record.tokenGenesis;
		this.assetList = record.assetList;
		this.defaultDepFee = record.defaultDepFee;
		this.defaultWithFee = record.defaultWithFee;
	}

	/* add a custom asset to the list for this chain
	 * @param asset (a ChainAsset)
	 */
	addAsset(asset) {
		this.assetList.push(asset);
	}
}

// class to store the info for the currently connected blockchain
class ChainConnection {
	constructor() {
		// the current config
		this.chainConfig = new ChainConfig();

		// list of available chain configurations, indexed by chain Id
		this.availConfigs = new Map();

		// list of available MVOs on the currently connected chain
		this.MVOConf = new MVOs(this.chainConfig.chainId);
	}

	// initialize all available (supported) chain configs
	initConfigs() {
		// this will be an array of ChainConfigs
		chainConfigs.forEach((config) => {
			const conf = new ChainConfig();
			conf.config(config);
			this.availConfigs.set(config.chainId, conf);
		});
	}

	// method to record wallet type change (unused placeholder)
	setWalletType(wType) {
		if (wType !== null) {
			this.walletType = wType;
		}
	}

	/* method to look up config for new chainId and switch to it
	 * @param chainId the new chain Id (must be one of those we know about)
	 */
	selectChain(chainId) {
		const conf = this.availConfigs.get(chainId);
		if (conf !== undefined) {
			this.chainConfig = conf;
			return true;
		}
		console.error("No config found for chainId " + chainId);
		alert("Chain ID " + chainId + " is not supported by Enshroud dApp");
		return false;
	}
}

// =========================================

export default ChainConnection;
export { ChainConfig, ChainAsset };
