import React, { useEffect, useState } from 'react';
import { Image, View, Modal } from 'react-native';
import { Button, Text } from 'react-native-paper';

import { SessionTypes } from '@walletconnect/types';
import { getSdkError } from '@walletconnect/utils';

import { PairingModalProps } from '../types';
import styles from '../styles/stylesheet';
import { web3wallet } from '../utils/wallet-connect/WalletConnectUtils';
import { useAccounts } from '../context/AccountsContext';

const PairingModal = ({
  visible,
  currentProposal,
  setCurrentProposal,
  setModalVisible,
  setToastVisible,
}: PairingModalProps) => {
  const { accounts } = useAccounts();

  const url = currentProposal?.params?.proposer?.metadata.url;
  const icon = currentProposal?.params.proposer?.metadata.icons[0];

  const [walletConnectData, setWalletConnectData] = useState<{
    walletConnectMethods: string[];
    walletConnectEvents: string[];
    walletConnectChains: string[];
  }>({
    walletConnectMethods: [],
    walletConnectEvents: [],
    walletConnectChains: [],
  });

  useEffect(() => {
    if (!currentProposal) {
      return;
    }
    const { params } = currentProposal;
    const { requiredNamespaces } = params;
    Object.keys(requiredNamespaces).forEach(key => {
      switch (key) {
        case 'eip155':
          const {
            methods: ethMethods,
            events: ethEvents,
            chains: ethChains,
          } = currentProposal?.params?.requiredNamespaces.eip155;

          setWalletConnectData(prevData => {
            return {
              walletConnectMethods: [
                ...prevData.walletConnectMethods,
                ...ethMethods,
              ],
              walletConnectEvents: [
                ...prevData.walletConnectEvents,
                ...ethEvents,
              ],
              walletConnectChains: ethChains
                ? [...prevData.walletConnectChains, ...ethChains]
                : [...prevData.walletConnectChains],
            };
          });
          break;
        case 'cosmos':
          const {
            methods: cosmosMethods,
            events: cosmosEvents,
            chains: cosmosChains,
          } = currentProposal?.params?.requiredNamespaces.cosmos;

          setWalletConnectData(prevData => {
            return {
              walletConnectMethods: [
                ...prevData.walletConnectMethods,
                ...cosmosMethods,
              ],
              walletConnectEvents: [
                ...prevData.walletConnectEvents,
                ...cosmosEvents,
              ],
              walletConnectChains: cosmosChains
                ? [...prevData.walletConnectChains, ...cosmosChains]
                : [...prevData.walletConnectChains],
            };
          });
          break;
        default:
          throw new Error(`${key} not supported`);
      }
    });
  }, [currentProposal]);

  const handleAccept = async () => {
    if (currentProposal) {
      const { id, params } = currentProposal;
      const { requiredNamespaces, relays } = params;
      const namespaces: SessionTypes.Namespaces = {};

      Object.keys(requiredNamespaces).forEach(key => {
        let currentAddresses: string[];

        switch (key) {
          case 'eip155':
            if (accounts.ethAccounts.length > 0) {
              currentAddresses = accounts.ethAccounts.map(
                account => account.address,
              );
            }
            break;
          case 'cosmos':
            if (accounts.cosmosAccounts.length > 0) {
              currentAddresses = accounts.cosmosAccounts.map(
                account => account.address,
              );
            }
            break;
          default:
            throw new Error(`${key} not supported`);
        }

        const namespaceAccounts: string[] = [];
        requiredNamespaces[key].chains!.map((chain: any) => {
          currentAddresses.map(acc =>
            namespaceAccounts.push(`${chain}:${acc}`),
          );
        });

        namespaces[key] = {
          accounts: namespaceAccounts,
          methods: requiredNamespaces[key].methods,
          events: requiredNamespaces[key].events,
        };
      });

      await web3wallet.approveSession({
        id,
        relayProtocol: relays[0].protocol,
        namespaces,
      });

      setModalVisible(false);
      setToastVisible(true);
      setCurrentProposal(undefined);
      setWalletConnectData({
        walletConnectMethods: [],
        walletConnectEvents: [],
        walletConnectChains: [],
      });
    }
  };

  const handleReject = async () => {
    if (currentProposal) {
      const { id } = currentProposal;
      await web3wallet.rejectSession({
        id,
        reason: getSdkError('USER_REJECTED_METHODS'),
      });

      setModalVisible(false);
      setCurrentProposal(undefined);
      setWalletConnectData({
        walletConnectMethods: [],
        walletConnectEvents: [],
        walletConnectChains: [],
      });
    }
  };

  return (
    <Modal visible={visible} animationType="slide" transparent>
      <View style={styles.container}>
        <View style={styles.modalContentContainer}>
          {icon && (
            <Image
              style={styles.dappLogo}
              source={icon ? { uri: icon } : undefined}
            />
          )}

          <Text variant="bodyMedium">{url}</Text>
          <View style={styles.marginVertical8} />
          <Text variant="titleMedium">Connect to this site?</Text>
          <Text>Chains: {walletConnectData.walletConnectChains}</Text>

          <View style={styles.marginVertical8}>
            <Text variant="titleMedium">Methods Requested:</Text>
            {walletConnectData.walletConnectMethods.map(method => (
              <Text style={styles.centerText} key={method}>
                {method}
              </Text>
            ))}
          </View>

          <View style={styles.marginVertical8}>
            <Text variant="titleMedium">Events Requested:</Text>
            {walletConnectData.walletConnectEvents.map(event => (
              <Text style={styles.centerText} key={event}>
                {event}
              </Text>
            ))}
          </View>

          <View style={styles.flexRow}>
            <Button mode="contained" onPress={() => handleAccept()}>
              Accept
            </Button>
            <View style={styles.space} />
            <Button mode="outlined" onPress={() => handleReject()}>
              Cancel
            </Button>
          </View>
        </View>
      </View>
    </Modal>
  );
};

export default PairingModal;
