import React, { useCallback, useEffect, useState } from 'react';
import { Button, Snackbar, Text } from 'react-native-paper';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { TxBody, AuthInfo } from 'cosmjs-types/cosmos/tx/v1beta1/tx';

import { SignClientTypes } from '@walletconnect/types';
import { useNavigation } from '@react-navigation/native';
import {
  NativeStackNavigationProp,
  createNativeStackNavigator,
} from '@react-navigation/native-stack';

import SignMessage from './components/SignMessage';
import HomeScreen from './components/HomeScreen';
import SignRequest from './components/SignRequest';
import InvalidPath from './components/InvalidPath';
import PairingModal from './components/PairingModal';
import AddSession from './components/AddSession';
import WalletConnect from './components/WalletConnect';
import { StackParamsList } from './types';
import { web3wallet } from './utils/wallet-connect/WalletConnectUtils';
import { EIP155_SIGNING_METHODS } from './utils/wallet-connect/EIP155Lib';
import { getSignParamsMessage } from './utils/wallet-connect/Helpers';
import { useWalletConnect } from './context/WalletConnectContext';

const Stack = createNativeStackNavigator<StackParamsList>();

const App = (): React.JSX.Element => {
  const navigation =
    useNavigation<NativeStackNavigationProp<StackParamsList>>();

  const { requestSession, setRequestSession, setActiveSessions } =
    useWalletConnect();

  const [modalVisible, setModalVisible] = useState(false);
  const [toastVisible, setToastVisible] = useState(false);
  const [currentProposal, setCurrentProposal] = useState<
    SignClientTypes.EventArguments['session_proposal'] | undefined
  >();

  const onSessionProposal = useCallback(
    (proposal: SignClientTypes.EventArguments['session_proposal']) => {
      setModalVisible(true);
      setCurrentProposal(proposal);
    },
    [],
  );

  const onSessionRequest = useCallback(
    async (requestEvent: SignClientTypes.EventArguments['session_request']) => {
      const { topic, params } = requestEvent;
      const { request } = params;

      const requestSessionData =
        web3wallet.engine.signClient.session.get(topic);

      setRequestSession(requestSessionData);

      switch (request.method) {
        case EIP155_SIGNING_METHODS.PERSONAL_SIGN:
          navigation.navigate('SignRequest', {
            network: 'eth',
            address: request.params[1],
            message: getSignParamsMessage(request.params),
            requestEvent,
            requestSession,
          });

          break;
        case 'cosmos_signDirect':
          const message = {
            txbody: TxBody.toJSON(
              TxBody.decode(
                Uint8Array.from(
                  Buffer.from(request.params.signDoc.bodyBytes, 'hex'),
                ),
              ),
            ),
            authInfo: AuthInfo.toJSON(
              AuthInfo.decode(
                Uint8Array.from(
                  Buffer.from(request.params.signDoc.authInfoBytes, 'hex'),
                ),
              ),
            ),
          };
          navigation.navigate('SignRequest', {
            network: 'cosmos',
            address: request.params.signerAddress,
            message: JSON.stringify(message, undefined, 2),
            requestEvent,
            requestSession,
          });

          break;
        case 'cosmos_signAmino':
          navigation.navigate('SignRequest', {
            network: 'cosmos',
            address: request.params.signerAddress,
            message: request.params.signDoc.memo,
            requestEvent,
            requestSession,
          });

          break;
        default:
          throw new Error('Invalid method');
      }
    },
    [requestSession, setRequestSession, navigation],
  );

  const onSessionDelete = useCallback(() => {
    let sessions = web3wallet?.getActiveSessions();
    setActiveSessions(sessions);
  }, []);

  useEffect(() => {
    web3wallet?.on('session_proposal', onSessionProposal);
    web3wallet?.on('session_request', onSessionRequest);
    web3wallet?.on('session_delete', onSessionDelete);
    return () => {
      web3wallet?.off('session_proposal', onSessionProposal);
      web3wallet?.off('session_request', onSessionRequest);
      web3wallet?.off('session_delete', onSessionDelete);
    };
    //TODO: Investigate dependencies
  });

  return (
    <>
      <Stack.Navigator>
        <Stack.Screen
          name="Laconic"
          component={HomeScreen}
          options={{
            headerTitle: () => <Text variant="titleLarge">Laconic Wallet</Text>,
            headerBackVisible: false,
          }}
        />
        <Stack.Screen
          name="SignMessage"
          component={SignMessage}
          options={{
            headerTitle: () => <Text variant="titleLarge">Sign Message</Text>,
          }}
          initialParams={{ selectedNetwork: 'Ethereum' }}
        />
        <Stack.Screen
          name="SignRequest"
          component={SignRequest}
          options={{
            headerTitle: () => (
              <Text variant="titleLarge">Sign this message?</Text>
            ),
          }}
        />
        <Stack.Screen
          name="InvalidPath"
          component={InvalidPath}
          options={{
            headerTitle: () => <Text variant="titleLarge">Bad Request</Text>,
            headerBackVisible: false,
          }}
        />
        <Stack.Screen
          name="WalletConnect"
          component={WalletConnect}
          options={{
            headerTitle: () => <Text variant="titleLarge">WalletConnect</Text>,
            headerRight: () => (
              <Button
                onPress={() => {
                  navigation.navigate('AddSession');
                }}>
                {<Icon name={'qrcode-scan'} size={20} />}
              </Button>
            ),
          }}
        />

        <Stack.Screen
          name="AddSession"
          component={AddSession}
          options={{
            title: 'New session',
          }}
        />
      </Stack.Navigator>
      <PairingModal
        visible={modalVisible}
        setModalVisible={setModalVisible}
        currentProposal={currentProposal}
        setCurrentProposal={setCurrentProposal}
        setToastVisible={setToastVisible}
      />
      <Snackbar
        visible={toastVisible}
        onDismiss={() => setToastVisible(false)}
        action={{
          label: 'Ok',
          onPress: () => {
            setToastVisible(false);
          },
        }}>
        Session approved
      </Snackbar>
    </>
  );
};

export default App;
