import React, {useState} from "react";
import "./App.css";

import Web3 from "web3";
import { WagmiConfig, createClient, configureChains, mainnet, useConnect, useAccount, useDisconnect } from "wagmi"

import { MetaMaskConnector } from "wagmi/connectors/metaMask"
import { publicProvider } from "wagmi/providers/public"

const web3 = new Web3(Web3.givenProvider);

import Airdrop from "./Airdrop.json";
import MagnaToken from "./MagnaToken.json";


const magnaTokenAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
const magnaTokenContract = new web3.eth.Contract(MagnaToken.abi as any, magnaTokenAddress);

const airdropAddress = "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512";
const airdropContract = new web3.eth.Contract(Airdrop.abi as any, airdropAddress);

const { chains, provider, webSocketProvider } = configureChains([mainnet], [publicProvider()]);

const wagmiClient = createClient({
    autoConnect: true,
    connectors: [
        new MetaMaskConnector({ chains }),
    ],
    provider,
    webSocketProvider,
})


function Connector() {
    const { connect, connectors, error, isLoading, pendingConnector } =
    useConnect()

    const { address, connector, isConnected } = useAccount()
    const { disconnect } = useDisconnect()

    if (isConnected) {
        const connectorName = connector?.name || "unknown connector";
        return (
            <div>
                <div>Connected to {connectorName}!</div>
                <div>Connected account: <b>{address}</b></div>
                <button onClick={(_evt) => disconnect() }>Disconnect</button>
            </div>
        )
    }

    return (
        <div className="connector">
            <div>Not currently connected to a wallet. Connect to...</div>
            {connectors.map((connector) => (
                <button
                    className="connectorButton"
                    disabled={!connector.ready}
                    key={connector.id}
                    onClick={() => connect({ connector })}
                >
                    {connector.name}
                    {!connector.ready && " (unsupported)"}
                    {isLoading &&
            connector.id === pendingConnector?.id &&
            " (connecting)"}
                </button>
            ))}
 
            {error && <div>{error.message}</div>}
        </div>
    )
}



interface AddressesProps {
    airdropButtonDisabled: boolean;
    performAirdrop: any;
    addressList: string[];
    setAddressListFn: any;
    numTokens: number;
    setNumTokens: any;
}

function Addresses(props: AddressesProps) {
    const [inputState, setInputState] = useState("");
    const [errorText, setErrorText] = useState("");
    const { airdropButtonDisabled, performAirdrop, setAddressListFn, addressList, numTokens, setNumTokens } = props;

    const save = () => {
        if (!web3.utils.isAddress(inputState)) {
            setErrorText("Invalid ETH address");
            return;
        }
        setErrorText("");

        const checksumAddr = web3.utils.toChecksumAddress(inputState);

        if (addressList.includes(checksumAddr)) {
            //Do nothing
        } else {
            setAddressListFn([...addressList, checksumAddr]);
        }
        setInputState("");
    }

    var num;
    if (isNaN(numTokens) || numTokens < 0) {
        num = 0;
    } else {
        num = numTokens;
    }

    return (
        <section className="airdropSettings">
            <p>Add an address to airdrop to:</p>
            <div>
                <input id="address" value={inputState} onChange={ (evt) => setInputState(evt.target.value) } ></input>
                <div className="addressError">{errorText}</div>
                <button onClick={save}>Add address</button>
            </div>
            <div>
                <div>Number of tokens:</div>
                <input type="numeric" value={num} onChange={ (evt) => setNumTokens(parseInt(evt.target.value)) }></input>
            </div>
            <div>
                <button disabled={airdropButtonDisabled} onClick={performAirdrop} >Perform Airdrop!</button>
            </div>
        </section>
    );
}

interface AddressListProps {
    addressList: string[];
};

function AddressList({addressList}: AddressListProps) {

    const addresses = addressList.length == 0 ?
        <p>No addresses specified yet</p> :
        addressList.map((addr: string) => <div key={addr} className="addressItem">{addr}</div>);
    return (
        <div className="addressList">
            <h2>Addresses to airdrop to: </h2>
            { addresses }
        </div>
    )
}

function App() {
    const [addressList, setAddressList] = useState([]);
    const [numTokens, setNumTokens] = useState(0);
    const { address: ownerAddress, isConnected } = useAccount()

    async function performAirdrop() {
        console.log("Performing airdrop");
        const totalCoins = addressList.length * numTokens;

        console.log(`Owner ${ownerAddress} Airdrop ${airdropAddress}`);

        const oldbal = await magnaTokenContract.methods.balanceOf(addressList[0]).call({ from: ownerAddress });
        console.log(`Old balance of magna token for ${addressList[0]} is ${oldbal}`);

        const allowance = await magnaTokenContract.methods.allowance(ownerAddress, airdropAddress).call({ from: ownerAddress });
        console.log(`Allowance: ${allowance}`);

        if (allowance < totalCoins) {
            const output = await magnaTokenContract.methods.approve(airdropAddress, totalCoins).send({ from: ownerAddress });
            console.log(output);
        }

        const recipients = addressList;
        const amounts = addressList.map((_addr) => numTokens);

        const output = await airdropContract.methods.airdropTokens(recipients, amounts).send({ from: ownerAddress });
        console.log(output);

        const newbal = await magnaTokenContract.methods.balanceOf(addressList[0]).call({ from: ownerAddress });
        console.log(`New balance of magna token for ${addressList[0]} is ${newbal}`);
    }

    const airdropButtonDisabled = addressList.length == 0 || !isConnected;

    return (
        <WagmiConfig client={wagmiClient}>
            <div className="App">
                <div className="sidebar">
                    <h1>Airdrop App</h1>
                    <Connector/>
                </div>
                <main className="main">
                    <p>Enter your airdropping settings:</p>
                    <section className="airdropPanel">
                        <Addresses airdropButtonDisabled={airdropButtonDisabled} performAirdrop={() => performAirdrop()} addressList={addressList} setAddressListFn={setAddressList} numTokens={numTokens} setNumTokens={setNumTokens}/>
                        <AddressList addressList={addressList} />
                    </section>
                </main>

            </div>
        </WagmiConfig>
    );
}

export default App;
