import { BitgetWallet } from './BitgetWallet.js';

export const allProviders = {
  4: BitgetWallet
}

export class BlockChain {
  constructor() {
    if (BlockChain.instance) {
      return BlockChain.instance;
    }
  
    this.initWallet();
    BlockChain.instance = this;
  }

  initWallet() {
    // console.log("init blockchain instance");
    // console.log(this.store.address);
    if (!this.store.address) {
      // console.log("no wallet login");
      return;
    } else {
      this.restoreWallet(this.store.walletType)
    }
  }

  preparePassport() {
    new PassportWallet();
  }

  async updateInfo({provider, accounts}) {
    this.web3Provider = provider
    if (!this.store.token) {
      const {token, refreshToken}= await this.wallet.getAccessToken();
      this.store.token = token
      this.store.refreshToken = refreshToken
    } else {
      if (isTokenExpired(3600, this.store.token)) {
        if (this.store.refreshToken && !isTokenExpired(300, this.store.refreshToken)) {
          const {token, refreshToken} = await genRefreshToken(this.store.refreshToken);
          this.store.token = token;
          this.store.refreshToken = refreshToken;
        } else {
          const {token, refreshToken}= await this.wallet.getAccessToken();
          this.store.token = token
          this.store.refreshToken = refreshToken
        }
      }
    }
    this.store.address = accounts[0];
    if (this.store.walletType == 3) {
      this.store.passportAddress = accounts[0];
      this.passportProvider = provider;
    } else {
      this.store.eoaAddress = accounts[0];
      this.eoaProvider = provider;
    }
    this.store.$persist();
    this.market.updateProvider(provider);
    this.widgets.initWidget();
    return provider;
  }

  async restoreWallet(walletType) {
    this.wallet = new allProviders[walletType](this);
    const { provider, accounts } = await this.wallet.web3Provider();
    await this.updateInfo({provider, accounts })
    if ((walletType == 1 || walletType == 2 || walletType == 4) && this.store.passportAddress) {
      await this.appendPassport();
    } else if (walletType == 3 && this.store.eoaType) {
      await this.restoreEoa();
    }
    return provider;
  }

  async connect() {
    // if this only one provider configed, use it directly
    if (ALL_PROVIDERS.length === 1) {
      const walletType = ALL_PROVIDERS[0].id
      this.wallet = new allProviders[walletType]();
      this.store.walletType = walletType;
      const { provider, accounts } = await this.wallet.web3Provider();
      await this.updateInfo({ provider, accounts })
      return provider;
    }
    const rewardModal = createModal(WalletSelectModel, {});
    const result = await rewardModal.show();
    if (!result.errcode) {
      this.store.walletType = result.wallet;
      this.wallet = new allProviders[result.wallet]();
      await this.updateInfo(result)
      if (result.wallet !== 3 && this.store.passportAddress) {
        await this.appendPassport();
      }
      return result.provider
    } else {
      console.log(`select result : ${result.errmsg}`);
      throw new Error(result.errmsg);
    }
  }
  /**
   * 用于eoa登录后, 添加passport地址
   */
  async appendPassport() {
    if (this.store.walletType == 3) {
      return;
    }
    let wallet = new PassportWallet();
    const { provider, accounts } = await wallet.web3Provider();
    this.passportProvider = provider;
    this.store.passportAddress = accounts[0];
    this.store.$persist();
  }

  /**
   * 用于passport登录后, 添加eoa地址
   */
  async appendEoa({title, subTitle}) {
    if (this.store.walletType != 3) {
      return;
    }
    const rewardModal = createModal(WalletSelectModel, {
      title: title || 'Select Address',
      message: subTitle || 'Please select the address you want to use',
      initData: { 1: 'MetaMask', 2: 'OKX Wallet', 3: 'Passport' },
      disabled: [3]
    });
    const { errcode, errmsg, walletInstance, wallet, provider, accounts } = await rewardModal.show();
    if (errcode) {
      console.log(`select address result : ${errmsg}`);
      throw new Error(errmsg);
    }
    this.eoaProvider = provider;
    this.eoaWallet = walletInstance;
    this.store.eoaAddress = accounts[0];
    this.store.eoaType = wallet;
    this.store.$persist();
  }

  async token() {
    const suffix = (this.store.walletType == 2 || this.store.walletType == 1 || this.store.walletType == 4) ? '.cf' : ''
    let token = this.store.token;
    if (!suffix && this.store.walletType == 3) {
      const res = await this.wallet.getAccessToken();
      token = res.token
    }
    if (!token) {
      return ''
    }
    
    return token+suffix
  }



  async logout() {
    if (this.store.walletType != 3 && this.passportProvider) {
      new PassportWallet().logout();
    } else if (this.store.walletType == 3 && this.eoaWallet) {
      await this.eoaWallet.logout();
    }
    this.store.reset();
    this.store.$persist();
    await this.wallet.logout();
    this.widgets.removeAll();
  }

  async getChainId() {
    return this.wallet.getChainId();
  }

  async getEoaChainId(provider) {
    const chainId = await provider.provider.request({ method: "eth_chainId" });
    return parseInt(chainId);
  }
  /**
   * 检查并切换到目标链, 各上链前须调用该方法
   */
  async checkAndChangeChain(targetChainId, provider) {
    targetChainId = targetChainId || cfgChainId;
    // passport只支持imtbl链, 不需要切换
    if (!provider && this.store.walletType == 3) {
      return
    }
    provider = provider || this.web3Provider;
    let chainId = await this.getEoaChainId(provider);
    if (chainId !== targetChainId) {
      console.log(`current chain: ${chainId}, want: ${targetChainId}`)
      chainId = await switchEthereumChain(provider.provider, targetChainId);
    }
    let eoaAddress;
    if (this.store.walletType == 3) {
      const { provider, accounts } = await this.eoaWallet.web3Provider();
      this.eoaProvider = provider;
      eoaAddress = accounts[0];
    } else {
      const { provider, accounts } = await this.wallet.web3Provider();
      this.web3Provider = provider;
      this.eoaProvider = provider;
      eoaAddress = accounts[0];
    }
    if (this.store.eoaAddress !== eoaAddress) {
      throw new Error('eoa address changed')
    }
  }

  async checkPassportLogin() {
    let needLogin = false;
    if (this.store.walletType != 3) {
      if (!this.store.passportAddress) {
        needLogin = true;
      }
    }
    if (needLogin) {
      const confirmResult = await createModal(ConfirmDialog, {
        title: 'Need login to Passport', 
        message: 'Are you sure you want to login with Passport?'
      }).show()
      if (confirmResult.errcode) {
        console.log('user cancel')
        throw new Error('user cancel')
      }
      await this.appendPassport();
    }
  }

  async selectAddress({title, subTitle, targetChainId}) {
    const initData = {}
    initData[this.store.walletType] = this.store.address
    const rewardModal = createModal(WalletSelectModel, {
      title: title || 'Select Address',
      message: subTitle || 'Please select the address you want to use',
      subTitle: subTitle,
      initData: { 1: 'MetaMask', 2: 'OKX Wallet', 3: 'Passport' }
    });
    const { errcode, errmsg, walletInstance, provider, accounts } = await rewardModal.show();
    if (errcode) {
      console.log(`select address result : ${errmsg}`);
      throw new Error(errmsg);
    }
    targetChainId = targetChainId || cfgChainId;
    let chainId = await walletInstance.getChainId();
    if (chainId !== targetChainId) {
      console.log(`current chain: ${chainId}, want: ${targetChainId}`)
      chainId = await switchEthereumChain(provider.provider, targetChainId);
    }
    return { provider, address: accounts[0] };
  }

  
}
