// Copyright (c) 2020-2021 Drew Lemmy
// This file is part of TenebraWeb 2 under AGPL-3.0.
// Full details: https://github.com/tmpim/TenebraWeb2/blob/master/LICENSE.txt
import { store } from "@app";
import * as actions from "@actions/WalletsActions";
import * as contactActions from "@actions/ContactsActions";

import { getWalletKey, parseWallet, syncWallet } from "@wallets";
import { getContactKey, parseContact } from "@contacts";

// Required for Safari
import "broadcastchannel-polyfill";

import Debug from "debug";
const debug = Debug("tenebraweb:storage-broadcast");

export const channel = new BroadcastChannel("tenebraweb:storage");

export function broadcastAddWallet(id: string): void {
  debug("broadcasting addWallet event for wallet id %s", id);
  channel.postMessage(["addWallet", id]);
}

export function broadcastEditWallet(id: string): void {
  debug("broadcasting editWallet event for wallet id %s", id);
  channel.postMessage(["editWallet", id]);
}

export function broadcastDeleteWallet(id: string): void {
  debug("broadcasting deleteWallet event for wallet id %s", id);
  channel.postMessage(["deleteWallet", id]);
}

export function broadcastAddContact(id: string): void {
  debug("broadcasting deleteContact event for contact id %s", id);
  channel.postMessage(["deleteContact", id]);
}

export function broadcastEditContact(id: string): void {
  debug("broadcasting editContact event for contact id %s", id);
  channel.postMessage(["editContact", id]);
}

export function broadcastDeleteContact(id: string): void {
  debug("broadcasting deleteContact event for contact id %s", id);
  channel.postMessage(["deleteContact", id]);
}

/** Component that manages a BroadcastChannel responsible for dispatching wallet
 * storage events (add, edit, delete) across tabs. */
export function StorageBroadcast(): JSX.Element | null {
  debug("registering storage broadcast event listener");
  channel.onmessage = e => {
    debug("received storage broadcast:", e);

    if (Array.isArray(e.data)) {
      const [type, ...data] = e.data;

      if (type === "addWallet" || type === "editWallet") {
        // ---------------------------------------------------------------------
        // addWallet, editWallet
        // ---------------------------------------------------------------------
        const id: string = data[0];
        const key = getWalletKey(id);

        // Load the wallet from localStorage (the update should've been
        // synchronous)
        const wallet = parseWallet(id, localStorage.getItem(key));
        debug("%s broadcast %s", type, id);

        // Dispatch the new/updated wallet to the Redux store
        if (type === "addWallet") store.dispatch(actions.addWallet(wallet));
        else store.dispatch(actions.updateWallet(id, wallet));

        syncWallet(wallet, true);
      } else if (type === "deleteWallet") {
        // ---------------------------------------------------------------------
        // deleteWallet
        // ---------------------------------------------------------------------
        const id: string = data[0];
        debug("addWallet broadcast %s", id);
        store.dispatch(actions.removeWallet(id));
      } else if (type === "addContact" || type === "editContact") {
        // ---------------------------------------------------------------------
        // addContact, editContact
        // ---------------------------------------------------------------------
        const id: string = data[0];
        const key = getContactKey(id);

        // Load the contact from localStorage (the update should've been
        // synchronous)
        const contact = parseContact(id, localStorage.getItem(key));
        debug("%s broadcast %s", type, id);

        // Dispatch the new/updated contact to the Redux store
        if (type === "addContact") store.dispatch(contactActions.addContact(contact));
        else store.dispatch(contactActions.updateContact({ id, contact }));
      } else if (type === "deleteContact") {
        // ---------------------------------------------------------------------
        // deleteContact
        // ---------------------------------------------------------------------
        const id: string = data[0];
        debug("deleteContact broadcast %s", id);
        store.dispatch(contactActions.removeContact(id));
      } else {
        debug("received unknown broadcast msg type %s", type);
      }
    }
  };

  return null;
}
