import { default as debounceFn } from "lodash.debounce";
import { useCallback, useContext, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";

import { useLogout } from "../../hooks/api/auth";
import { queryClient } from "../../lib/query-client";
import { KeybindContext } from "./keybind-context";
import { Shortcut } from "./types";
import { findShortcut } from "./utils";

export const useKeybind = () => {
  const context = useContext(KeybindContext);

  if (!context) {
    throw new Error("useKeybind must be used within a KeybindProvider");
  }

  return context;
};

export const useRegisterShortcut = () => {};

export const useShortcuts = ({
  shortcuts = [],
  debounce,
}: {
  shortcuts?: Shortcut[];
  debounce: number;
}) => {
  const [keys, setKeys] = useState<string[]>([]);
  const navigate = useNavigate();

  // eslint-disable-next-line react-hooks/exhaustive-deps
  const removeKeys = useCallback(
    debounceFn(() => setKeys([]), debounce),
    [],
  );

  // eslint-disable-next-line react-hooks/exhaustive-deps
  const invokeShortcut = useCallback(
    debounceFn((shortcut: Shortcut | null) => {
      if (shortcut && shortcut.callback) {
        shortcut.callback();
        setKeys([]);

        return;
      }

      if (shortcut && shortcut.to) {
        navigate(shortcut.to);
        setKeys([]);

        return;
      }
    }, debounce / 2),
    [],
  );

  useEffect(() => {
    if (keys.length > 0 && shortcuts.length > 0) {
      const shortcut = findShortcut(shortcuts, keys);
      invokeShortcut(shortcut);
    }

    return () => invokeShortcut.cancel();
  }, [keys, shortcuts, invokeShortcut]);

  useEffect(() => {
    const listener = (event: KeyboardEvent) => {
      const target = event.target as HTMLElement;

      /**
       * Ignore key events from input, textarea and contenteditable elements
       */
      if (
        target.tagName === "INPUT" ||
        target.tagName === "TEXTAREA" ||
        target.contentEditable === "true"
      ) {
        removeKeys();
        return;
      }

      setKeys((oldKeys) => [...oldKeys, event.key]);
      removeKeys();
    };

    window.addEventListener("keydown", listener);

    return () => {
      window.removeEventListener("keydown", listener);
    };
  }, [removeKeys]);
};

export const useGlobalShortcuts = () => {
  const { t } = useTranslation();
  const navigate = useNavigate();

  const { mutateAsync } = useLogout();

  const handleLogout = async () => {
    await mutateAsync(undefined, {
      onSuccess: () => {
        queryClient.clear();
        navigate("/login");
      },
    });
  };

  const globalShortcuts: Shortcut[] = [
    // Pages
    {
      keys: {
        Mac: ["G", "O"],
      },
      label: t("app.keyboardShortcuts.navigation.goToOrders"),
      type: "pageShortcut",
      to: "/orders",
    },
    {
      keys: {
        Mac: ["G", "P"],
      },
      label: t("app.keyboardShortcuts.navigation.goToProducts"),
      type: "pageShortcut",
      to: "/products",
    },
    {
      keys: {
        Mac: ["G", "C"],
      },
      label: t("app.keyboardShortcuts.navigation.goToCollections"),
      type: "pageShortcut",
      to: "/collections",
    },
    {
      keys: {
        Mac: ["G", "A"],
      },
      label: t("app.keyboardShortcuts.navigation.goToCategories"),
      type: "pageShortcut",
      to: "/categories",
    },
    {
      keys: {
        Mac: ["G", "U"],
      },
      label: t("app.keyboardShortcuts.navigation.goToCustomers"),
      type: "pageShortcut",
      to: "/customers",
    },
    {
      keys: {
        Mac: ["G", "I"],
      },
      label: t("app.keyboardShortcuts.navigation.goToInventory"),
      type: "pageShortcut",
      to: "/inventory",
    },
    {
      keys: {
        Mac: ["G", "L"],
      },
      label: t("app.keyboardShortcuts.navigation.goToPriceLists"),
      type: "pageShortcut",
      to: "/price-lists",
    },
    {
      keys: {
        Mac: ["G", "M"],
      },
      label: t("app.keyboardShortcuts.navigation.goToPromotions"),
      type: "pageShortcut",
      to: "/promotions",
    },
    {
      keys: {
        Mac: ["G", "K"],
      },
      label: t("app.keyboardShortcuts.navigation.goToCampaigns"),
      type: "pageShortcut",
      to: "/campaigns",
    },
    // Settings
    {
      keys: {
        Mac: ["G", ","],
      },
      label: t("app.keyboardShortcuts.settings.goToSettings"),
      type: "settingShortcut",
      to: "/settings",
    },
    {
      keys: {
        Mac: ["G", ",", "S"],
      },
      label: t("app.keyboardShortcuts.settings.goToStore"),
      type: "settingShortcut",
      to: "/settings/store",
    },
    {
      keys: {
        Mac: ["G", ",", "P"],
      },
      label: t("app.keyboardShortcuts.settings.goToProductTypes"),
      type: "settingShortcut",
      to: "/settings/product-types",
    },
    {
      keys: {
        Mac: ["G", ",", "L"],
      },
      label: t("app.keyboardShortcuts.settings.goToLocations"),
      type: "settingShortcut",
      to: "/settings/locations",
    },
    // Commands
    {
      keys: {
        Mac: ["B", "Y", "E"],
      },
      label: t("actions.logout"),
      type: "commandShortcut",
      callback: () => handleLogout(),
    },
  ];

  return globalShortcuts;
};
