import React, { useEffect, useMemo, useState } from 'react';
import { Image, View, Modal, ScrollView } from 'react-native';
import { Button, Text } from 'react-native-paper';
import { SvgUri } from 'react-native-svg';
import mergeWith from 'lodash/mergeWith';

import { buildApprovedNamespaces, 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';
import { useWalletConnect } from '../context/WalletConnectContext';
import { useNetworks } from '../context/NetworksContext';
import { getNamespaces } from '../utils/wallet-connect/helpers';

const PairingModal = ({
  visible,
  currentProposal,
  setCurrentProposal,
  setModalVisible,
  setToastVisible,
}: PairingModalProps) => {
  const { accounts, currentIndex } = useAccounts();
  const { selectedNetwork, networksData } = useNetworks();
  const [isLoading, setIsLoading] = useState(false);

  const dappName = currentProposal?.params?.proposer?.metadata.name;
  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: [],
  });

  const [supportedNamespaces, setSupportedNamespaces] = useState<
    Record<
      string,
      {
        chains: string[];
        methods: string[];
        events: string[];
        accounts: string[];
      }
    >
  >();

  useEffect(() => {
    if (!currentProposal) {
      return;
    }
    const { params } = currentProposal;
    const { requiredNamespaces, optionalNamespaces } = params;

    setWalletConnectData({
      walletConnectMethods: [],
      walletConnectEvents: [],
      walletConnectChains: [],
    });

    const combinedNamespaces = mergeWith(
      requiredNamespaces,
      optionalNamespaces,
      (obj, src) =>
        Array.isArray(obj) && Array.isArray(src) ? [...src, ...obj] : undefined,
    );

    Object.keys(combinedNamespaces).forEach(key => {
      const { methods, events, chains } = combinedNamespaces[key];

      setWalletConnectData(prevData => {
        return {
          walletConnectMethods: [...prevData.walletConnectMethods, ...methods],
          walletConnectEvents: [...prevData.walletConnectEvents, ...events],
          walletConnectChains: chains
            ? [...prevData.walletConnectChains, ...chains]
            : [...prevData.walletConnectChains],
        };
      });
    });
  }, [currentProposal]);

  const { setActiveSessions } = useWalletConnect();

  useEffect(() => {
    const getSupportedNamespaces = async () => {
      if (!currentProposal) {
        return;
      }

      const { optionalNamespaces, requiredNamespaces } = currentProposal.params;

      const nameSpaces = await getNamespaces(
        optionalNamespaces,
        requiredNamespaces,
        networksData,
        selectedNetwork,
        accounts,
        currentIndex,
      );

      setSupportedNamespaces(nameSpaces);
    };

    getSupportedNamespaces();
  }, [currentProposal, networksData, selectedNetwork, accounts, currentIndex]);

  const namespaces = useMemo(() => {
    return (
      currentProposal &&
      supportedNamespaces &&
      buildApprovedNamespaces({
        proposal: currentProposal.params,
        supportedNamespaces,
      })
    );
  }, [currentProposal, supportedNamespaces]);

  const handleAccept = async () => {
    try {
      if (currentProposal && namespaces) {
        setIsLoading(true);
        const { id } = currentProposal;

        await web3wallet!.approveSession({
          id,
          namespaces,
        });

        const sessions = web3wallet!.getActiveSessions();
        setIsLoading(false);
        setActiveSessions(sessions);
        setModalVisible(false);
        setToastVisible(true);
        setCurrentProposal(undefined);
        setSupportedNamespaces(undefined);
        setWalletConnectData({
          walletConnectMethods: [],
          walletConnectEvents: [],
          walletConnectChains: [],
        });
      }
    } catch (error) {
      console.error('Error in approve session:', error);
      throw error;
    }
  };

  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={{ flex: 1 }}>
        <View style={styles.modalContentContainer}>
          <ScrollView showsVerticalScrollIndicator={true}>
            <View style={styles.container}>
              {icon && (
                <>
                  {icon.endsWith('.svg') ? (
                    <View style={styles.dappLogo}>
                      <SvgUri height="50" width="50" uri={icon} />
                    </View>
                  ) : (
                    <Image style={styles.dappLogo} source={{ uri: icon }} />
                  )}
                </>
              )}

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

              {walletConnectData.walletConnectMethods.length > 0 && (
                <View>
                  <Text variant="titleMedium">Chains:</Text>
                  {walletConnectData.walletConnectChains.map(chain => (
                    <Text style={styles.centerText} key={chain}>
                      {chain}
                    </Text>
                  ))}
                </View>
              )}

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

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

          <View style={styles.flexRow}>
            <Button mode="contained" onPress={handleAccept} loading={isLoading}>
              {isLoading ? 'Connecting' : 'Yes'}
            </Button>
            <View style={styles.space} />
            <Button mode="outlined" onPress={handleReject}>
              No
            </Button>
          </View>
        </View>
      </View>
    </Modal>
  );
};

export default PairingModal;
