/*
 * Copyright (c) 2022 @automata-network/wallet-sdk authors and contributors.
 * This software may be modified and distributed under the terms of UNLICENSED
 * license. Refer to the LICENSE file for details.
 */
import React, { useEffect, useState } from 'react'

import { Injected } from '@polkadot/extension-inject/types'
import { WalletReadyState } from '@solana/wallet-adapter-base'
import { useWallet as useSolanaAdapterReactWallet } from '@solana/wallet-adapter-react'

import { useSolanaConnectorContext } from '../../store/solana-connector/hook'
import { userCanceledError } from '../../utils'
import { Connector, ConnectorItem } from '../Connector/Connector'

interface ConnectorContextData {
  loading: boolean
  injected?: Injected
  error?: Error
}

const initialConnectorContextData = {
  loading: false,
  error: undefined
}

export const SolanaConnector: React.FC = () => {
  const { visible, setVisible, connectionPromise } = useSolanaConnectorContext()
  const { select, wallets, wallet, connect } = useSolanaAdapterReactWallet()
  const [data, setData] = useState<ConnectorContextData>(initialConnectorContextData)
  const [walletConnecting, setWalletConnecting] = useState(false)
  const [walletWaitingResolve, setWalletWaitingResolve] = useState(false)

  async function getAdapter(index: number) {
    setData({ loading: true })

    try {
      select(wallets[index].adapter.name)

      setWalletConnecting(true)
    } catch (e) {
      if (connectionPromise) {
        connectionPromise.reject(e as Error)
      }

      setData({ loading: false, error: e as Error })

      throw e
    }
  }

  async function connectWallet() {
    if (walletConnecting) {
      setWalletConnecting(false)

      try {
        await connect()
      } catch (e) {
        if (connectionPromise) {
          connectionPromise.reject(e as Error)
        }

        setData({ loading: false, error: e as Error })

        throw e
      }

      setWalletWaitingResolve(true)
    }
  }

  useEffect(() => {
    connectWallet()
  }, [connect, walletConnecting])

  useEffect(() => {
    if (walletWaitingResolve && wallet) {
      setWalletWaitingResolve(false)

      if (connectionPromise) {
        const { name, icon } = wallet.adapter

        connectionPromise.resolve({
          label: name,
          icon,
          adapter: wallet.adapter,
          accounts: wallet.adapter.publicKey ? [wallet.adapter.publicKey.toString()] : []
        })
      }

      setVisible(false)

      setData(initialConnectorContextData)
    }
  }, [walletWaitingResolve, wallet])

  return visible ? (
    <Connector
      loading={data.loading}
      error={data.error}
      items={
        wallets
          .map((item) => {
            const { url, icon, name, readyState } = item.adapter
            const enabled =
              readyState === WalletReadyState.Installed || readyState === WalletReadyState.Loadable

            return enabled || url ? { enabled, link: url, icon, label: name } : undefined
          })
          .filter((item) => item != null) as ConnectorItem[]
      }
      onSelect={(index) => {
        getAdapter(index)
      }}
      onClose={() => {
        setVisible(false)

        connectionPromise?.reject(userCanceledError)
      }}
    />
  ) : null
}
