import '@ethersproject/shims';

import React, { useEffect, useState } from 'react';
import './App.css';
import { Waku } from 'js-waku';
import { Signer } from '@ethersproject/abstract-signer';
import { KeyPair } from './crypto';
import { Message } from './messaging/Messages';
import 'fontsource-roboto';
import { AppBar, IconButton, Toolbar, Typography } from '@material-ui/core';
import KeyPairHandling from './key_pair_handling/KeyPairHandling';
import {
  createMuiTheme,
  ThemeProvider,
  makeStyles,
} from '@material-ui/core/styles';
import { teal, purple, green } from '@material-ui/core/colors';
import WifiIcon from '@material-ui/icons/Wifi';
import BroadcastPublicKey from './BroadcastPublicKey';
import Messaging from './messaging/Messaging';
import {
  DirectMessageContentTopic,
  handleDirectMessage,
  handlePublicKeyMessage,
  initWaku,
  PublicKeyContentTopic,
} from './waku';
import ConnectWallet from './ConnectWallet';

const theme = createMuiTheme({
  palette: {
    primary: {
      main: purple[500],
    },
    secondary: {
      main: teal[600],
    },
  },
});

const useStyles = makeStyles({
  root: {
    textAlign: 'center',
    display: 'flex',
    flexDirection: 'column',
    minHeight: '100vh',
  },
  appBar: {
    // height: '200p',
  },
  container: {
    display: 'flex',
    flex: 1,
  },
  main: {
    flex: 1,
    margin: '10px',
  },
  wakuStatus: {
    marginRight: theme.spacing(2),
  },
  title: {
    flexGrow: 1,
  },
  peers: {},
});

function App() {
  const [waku, setWaku] = useState<Waku>();
  const [signer, setSigner] = useState<Signer>();
  const [EncryptionKeyPair, setEncryptionKeyPair] = useState<
    KeyPair | undefined
  >();
  const [publicKeys, setPublicKeys] = useState<Map<string, Uint8Array>>(
    new Map()
  );
  const [messages, setMessages] = useState<Message[]>([]);
  const [address, setAddress] = useState<string>();

  const classes = useStyles();

  // Waku initialization
  useEffect(() => {
    if (waku) return;
    initWaku()
      .then((_waku) => {
        console.log('waku: ready');
        setWaku(_waku);
      })
      .catch((e) => {
        console.error('Failed to initiate Waku', e);
      });
  }, [waku]);

  useEffect(() => {
    if (!waku) return;

    const observerPublicKeyMessage = handlePublicKeyMessage.bind(
      {},
      address,
      setPublicKeys
    );

    waku.relay.addObserver(observerPublicKeyMessage, [PublicKeyContentTopic]);

    return function cleanUp() {
      if (!waku) return;
      waku.relay.deleteObserver(observerPublicKeyMessage, [
        PublicKeyContentTopic,
      ]);
    };
  }, [waku, address]);

  useEffect(() => {
    if (!waku) return;
    if (!EncryptionKeyPair) return;

    waku.relay.addDecryptionKey(EncryptionKeyPair.privateKey);

    return function cleanUp() {
      if (!waku) return;
      if (!EncryptionKeyPair) return;

      waku.relay.deleteDecryptionKey(EncryptionKeyPair.privateKey);
    };
  }, [waku, EncryptionKeyPair]);

  useEffect(() => {
    if (!waku) return;
    if (!EncryptionKeyPair) return;
    if (!address) return;

    const observerDirectMessage = handleDirectMessage.bind(
      {},
      setMessages,
      address
    );

    waku.relay.addObserver(observerDirectMessage, [DirectMessageContentTopic]);

    return function cleanUp() {
      if (!waku) return;
      if (!observerDirectMessage) return;
      waku.relay.deleteObserver(observerDirectMessage, [
        DirectMessageContentTopic,
      ]);
    };
  }, [waku, address, EncryptionKeyPair]);

  let relayPeers = 0;
  let lightPushPeers = 0;
  if (waku) {
    relayPeers = waku.relay.getPeers().size;
    lightPushPeers = waku.lightPush.peers.length;
  }

  let addressDisplay = '';
  if (address) {
    addressDisplay =
      address.substr(0, 6) + '...' + address.substr(address.length - 4, 4);
  }

  return (
    <ThemeProvider theme={theme}>
      <div className={classes.root}>
        <AppBar className={classes.appBar} position="static">
          <Toolbar>
            <IconButton
              edge="start"
              className={classes.wakuStatus}
              aria-label="waku-status"
            >
              <WifiIcon
                color={waku ? undefined : 'disabled'}
                style={waku ? { color: green[500] } : {}}
              />
            </IconButton>
            <Typography className={classes.peers} aria-label="connected-peers">
              Peers: {relayPeers} relay, {lightPushPeers} light push
            </Typography>
            <Typography variant="h6" className={classes.title}>
              Ethereum Direct Message
            </Typography>
            <Typography>{addressDisplay}</Typography>
          </Toolbar>
        </AppBar>

        <div className={classes.container}>
          <main className={classes.main}>
            <fieldset>
              <legend>Wallet</legend>
              <ConnectWallet setAddress={setAddress} setSigner={setSigner} />
            </fieldset>
            <fieldset>
              <legend>Encryption Key Pair</legend>
              <KeyPairHandling
                encryptionKeyPair={EncryptionKeyPair}
                setEncryptionKeyPair={setEncryptionKeyPair}
              />
              <BroadcastPublicKey
                signer={signer}
                EncryptionKeyPair={EncryptionKeyPair}
                waku={waku}
              />
            </fieldset>
            <fieldset>
              <legend>Messaging</legend>
              <Messaging
                recipients={publicKeys}
                waku={waku}
                messages={messages}
              />
            </fieldset>
          </main>
        </div>
      </div>
    </ThemeProvider>
  );
}

export default App;
