import React from "react";

import * as _ from "lodash";
import { connect, WalletConnection, keyStores, Near } from 'near-api-js';
const { KeyProvisioner, ProvisionerConfig } = await import("../../../pkg/web_client");

class Wallet extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            isSignedIn: false,
            keyStore: new keyStores.BrowserLocalStorageKeyStore(),
            accountId: null,
            walletConnection: null,
            nearConnection: null,
            timeouts: {
                default_ms: 7000,
                interaction_ms: 30_000
            },
            provisioner: null,
            secretKey: null,
            meetingId: null,
            participants: [],
        };
    }

    setStateAsync(state) {
        return new Promise((resolve) => {
            this.setState(state, resolve)
        });
    }

    async componentDidMount() {
        let keyStore = this.state.keyStore;

        let nearConnectionCall = async () => {
            let connectionConfig = {
                networkId: "testnet",
                keyStore,
                nodeUrl: "https://rpc.testnet.near.org",
                walletUrl: "https://wallet.testnet.near.org",
                helperUrl: "https://helper.testnet.near.org",
                explorerUrl: "https://explorer.testnet.near.org",
            };

            let nearConnection = await connect(connectionConfig);
            return nearConnection;
        };

        let nearConnection = await nearConnectionCall();
        let walletConnection = new WalletConnection(nearConnection, null);

        await this.setStateAsync({ ...this.state, keyStore, nearConnection, walletConnection, accountId: walletConnection.getAccountId() })

        if (this.state.walletConnection.isSignedIn()) {
            await this.setStateAsync({ ...this.state, isSignedIn: true });
            await this.handleWallet();
        }
    }

    async requestSignIn() {
        if (!this.state.walletConnection.isSignedIn()) {
            await this.state.walletConnection.requestSignIn(this.state.accountId, "Test App");
        }
    }

    async handleWallet() {
        let accountId = this.state.accountId;
        let account = await this.state.nearConnection.account(accountId);
        let accessKeys = await account.getAccessKeys();
        let keypair = await this.state.keyStore.getKey("testnet", accountId);

        let found = accessKeys.find(key => key.public_key == keypair.getPublicKey().toString());

        let config = new ProvisionerConfig("relayz-meet.testnet", "https://rpc.testnet.near.org", "https://ks.relayz.io:3000");

        await this.setStateAsync({
            ...this.state,
            provisioner: new KeyProvisioner(keypair.toString(), BigInt(found.access_key.nonce), accountId, config)
        });

        console.log("KeyPair: ", keypair.getPublicKey().toString());
        console.log("Account: ", account);
    }

    async handleMeetingStart() {
        let participants = this.state.participants;
        let provisioner = this.state.provisioner;
        let default_ms = this.state.timeouts.default_ms;
        let interaction_ms = this.state.timeouts.interaction_ms;

        if (participants.length > 0) {
            console.log("Participants: " + participants);
            provisioner.init_meeting(new Set(participants), default_ms)
                .then((meeting) => {
                    this.props.setMeetingId(meeting.meet_id);
                    let meetingId = meeting.meet_id;
                    this.setState({ ...this.state, meetingId });
                    console.log("Meeting Id:", meeting.meet_id);
                    provisioner.send_keys(meeting.meet_id, interaction_ms)
                        .then((secretKey) => {
                            this.setState({ ...this.state, secretKey });
                            this.props.setSecretKey(secretKey);
                            console.log("Secret Key" + secretKey);
                        })
                        .then(() => console.log("Send keys is ok"))
                        .catch((err) => {
                            console.log("Error: ", err);
                        });
                })
                .then(() => console.log("Init is ok"))
                .catch((err) => {
                    console.log("Error: ", err);
                });
        }
    }

    async handleMeetingJoin() {
        if (this.state.meetingId.length == null) {
            return
        }
        let meetingId = this.state.meetingId;
        let provisioner = this.state.provisioner;
        let default_ms = this.state.timeouts.default_ms;
        this.props.setMeetingId(meetingId);

        provisioner.get_key(meetingId, default_ms).then((secretKey) => {
            this.props.setSecretKey(secretKey);
            this.setState({ ...this.state, secretKey });
            console.log("Secret Key" + secretKey);
        }).catch((err) => {
            console.log("Error: ", err);
        });
    }

    render() {
        return (
            <div className="container">
                <div className="moderator-part">
                    <label>Moderator part: </label>
                    <div className="sign-in">
                        <label>Account: </label>
                        <input
                            type="text"
                            disabled={this.state.isSignedIn}
                            onChange={e => this.setState({ accountId: e.target.value })}
                            defaultValue={this.state.accountId}
                        />
                        <button disabled={this.state.isSignedIn} onClick={() => this.requestSignIn()}>
                            Login
                        </button>
                    </div>

                    <div>
                        <label>Init meeting with participants:</label>
                        <input
                            type="text"
                            onBlur={e => this.setState({ participants: e.target.value.split(',').map((id) => id.trim()) })}
                        />
                        <button onClick={() => this.handleMeetingStart()}>Start Meeting</button>
                    </div>

                    <div>
                        <label>
                            Meeting ID: {this.state.meetingId}
                        </label>
                    </div>
                </div>

                <div className="end-user-part">
                    <label>End-user part: </label>
                    <div>
                        <label>Meeting ID: </label>
                        <input
                            type="text" id="inp_meeting_id" name="meeting"
                            onBlur={e => this.setState({ meetingId: e.target.value })}
                        />
                        <button id="join_meeting_id" onClick={() => this.handleMeetingJoin()}>Join Meeting</button>
                    </div>

                    <div>
                        <label>Secret: {this.state.secretKey}</label>
                    </div>
                </div>
            </div>
        );
    }
}

export default Wallet;
