import type { FC, MouseEvent } from "react";
import React, {
  useCallback,
  useLayoutEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import { createPortal } from "react-dom";

import Typography from "@mui/material/Typography";
import Dialog from "@mui/material/Dialog";
import DialogTitle from "@mui/material/DialogTitle";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
import DialogActions from "@mui/material/DialogActions";
import Button from "@mui/material/Button";
import type { WalletName } from "@solana/wallet-adapter-base";
import { Wallet, useWallet } from "@solana/wallet-adapter-react";

import { DemonWalletName, E2EWalletName } from "../adapters";
import {
  handleRedirectIfDemonNotInstalled,
  isDemonWalletDetected,
  openNewWindowWithCallback,
  getDemonWalletUrl,
  isMobileDevice,
} from "../helpers";
import { useWalletModal } from "../hooks";
import { WalletListItem } from "./WalletListItem";

export interface WalletModalProps {
  className?: string;
  container?: string;
}

const useHandleTabKey = () => {
  const ref = useRef<HTMLDivElement>(null);
  const { setVisible } = useWalletModal();
  const [fadeIn, setFadeIn] = useState(false);
  const [portal, setPortal] = useState<Element | null>(null);

  const handleTabKey = useCallback(
    (event: KeyboardEvent) => {
      const node = ref.current;
      if (!node) return;

      // here we query all focusable elements
      const focusableElements = node.querySelectorAll("button");
      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
      const firstElement = focusableElements[0]!;
      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
      const lastElement = focusableElements[focusableElements.length - 1]!;

      if (event.shiftKey) {
        // if going backward by pressing tab and firstElement is active, shift focus to last focusable element
        if (document.activeElement === firstElement) {
          lastElement.focus();
          event.preventDefault();
        }
      } else {
        // if going forward by pressing tab and lastElement is active, shift focus to first focusable element
        if (document.activeElement === lastElement) {
          firstElement.focus();
          event.preventDefault();
        }
      }
    },
    [ref],
  );

  const hideModal = useCallback(() => {
    setFadeIn(false);
    setTimeout(() => setVisible(false), 150);
  }, [setVisible]);

  useLayoutEffect(() => {
    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        hideModal();
      } else if (event.key === "Tab") {
        handleTabKey(event);
      }
    };

    // Get original overflow
    const { overflow } = window.getComputedStyle(document.body);
    // Hack to enable fade in animation after mount
    setTimeout(() => setFadeIn(true), 0);
    // Prevent scrolling on mount
    document.body.style.overflow = "hidden";
    // Listen for keydown events
    window.addEventListener("keydown", handleKeyDown, false);

    return () => {
      // Re-enable scrolling when component unmounts
      document.body.style.overflow = overflow;
      window.removeEventListener("keydown", handleKeyDown, false);
    };
  }, [hideModal, handleTabKey]);

  useLayoutEffect(() => setPortal(document.querySelector("body")));

  const handleClose = useCallback(
    (event: MouseEvent) => {
      event.preventDefault();
      hideModal();
    },
    [hideModal],
  );

  return { ref, handleTabKey, fadeIn, portal, handleClose, hideModal };
};

const DesktopExtensionInstallingConfirmationDialog = (props: {
  openNotice: boolean,
  handleCloseNotice: () => void,
  handleConfirmNotice: () => void,
}) => {
  const { trans } = useWalletModal();
  const { openNotice, handleCloseNotice, handleConfirmNotice } = props

  return (
    <Dialog
      open={openNotice}
      onClose={handleCloseNotice}
      aria-labelledby="alert-dialog-title"
      aria-describedby="alert-dialog-description"
    >
      <DialogTitle id="alert-dialog-title">
        {trans.install_carax_notice_heading}
      </DialogTitle>
      <DialogContent>
        <DialogContentText id="alert-dialog-description">
          {trans.install_carax_notice_body}
        </DialogContentText>
      </DialogContent>
      <DialogActions>
        <Button onClick={handleConfirmNotice} autoFocus>
          OK
        </Button>
      </DialogActions>
    </Dialog>
  )
}

const MobileAppInstallingConfirmation = (props: {
  hideModal: () => void,
  handleClose: (event: MouseEvent) => void,
}) => {
  const { trans } = useWalletModal();
  const { hideModal, handleClose } = props

  const handleConfirmRedirect = useCallback(() => {
    hideModal()
    handleRedirectIfDemonNotInstalled()
  }, [])

  return (
    <div className="confirm-open-demon-wallet">
      <p className="confirm-open-demon-wallet--confirm-message">
        {trans.connect_using_carax_app}
      </p>
      <div className="confirm-open-demon-wallet-btn-wrapper">
        <button className="confirm-button" onClick={handleClose}>{trans.cancel}</button>
        <button className="confirm-button confirm-button-confirm" onClick={handleConfirmRedirect}>OK</button>
      </div>
    </div>
  )
}

const WalletItemsListBody = (props: {
  handleClose: (event: MouseEvent) => void,
}) => {
  const { wallets, select, connect } = useWallet();
  const { trans } = useWalletModal();
  const [openNotice, setOpenNotice] = React.useState(false)
  const { handleClose } = props

  const demonWallet = useMemo(() => {
    return wallets.find(
      (wallet) =>
        wallet.adapter.name === DemonWalletName ||
        wallet.adapter.name === E2EWalletName,
    ) as Wallet
  }, [wallets]);

  const handleClickOpenNotice = useCallback(() => {
    setOpenNotice(true)
  }, [])
  const handleCloseNotice = useCallback(() => {
    setOpenNotice(false)
  }, [])
  const handleConfirmNotice = useCallback(() => {
    openNewWindowWithCallback(getDemonWalletUrl(), () => {
      // eslint-disable-next-line no-console
      console.log('New window has been closed!')
      if (!isDemonWalletDetected()) {
        window.location.reload()
      }
    })
  }, [])

  const handleWalletClick = useCallback((event: MouseEvent, walletName: WalletName) => {
    if (walletName === DemonWalletName) {
      if (!isDemonWalletDetected()) {
        handleClickOpenNotice()
        return
      }
    }
    select(walletName);
    handleClose(event);
  }, [
    handleClickOpenNotice,
    handleRedirectIfDemonNotInstalled,
    select,
    connect,
  ]);

  return (
    <>
      <div className="dialog-heading">
        <Typography className="dialog-heading__title">
          {trans.dialog_heading}
        </Typography>
      </div>
      <WalletListItem
        key={demonWallet.adapter.name}
        handleClick={(event) =>
          handleWalletClick(event, demonWallet.adapter.name)
        }
        wallet={demonWallet}
      />
      {!isMobileDevice && (
        <DesktopExtensionInstallingConfirmationDialog
          openNotice={openNotice}
          handleCloseNotice={handleCloseNotice}
          handleConfirmNotice={handleConfirmNotice}
        />
      )}
      <div className="first-time-connect-notice">
        <Typography className="first-time-connect-notice__text-content">
          {trans.first_time_connect_notice}
        </Typography>
      </div>
    </>
  )
}

export const WalletModal: FC<WalletModalProps> = ({ className = "" }) => {
  const { ref, fadeIn, portal, handleClose, hideModal } = useHandleTabKey();

  const renderContent = () => {
    if (isMobileDevice && !isDemonWalletDetected()) {
      return (
        <MobileAppInstallingConfirmation
          hideModal={hideModal}
          handleClose={handleClose}
        />
      )
    }

    return (
      <WalletItemsListBody
        handleClose={handleClose}
      />
    )
  }

  return (
    portal &&
    createPortal(
      <div
        aria-labelledby="wallet-adapter-modal-title"
        aria-modal="true"
        className={`wallet-adapter-modal ${
          fadeIn && "wallet-adapter-modal-fade-in"
        } ${className}`}
        ref={ref}
        role="dialog"
      >
        <div className="wallet-adapter-modal-container">
          <div className="wallet-adapter-modal-wrapper">
            <button
              onClick={handleClose}
              className="wallet-adapter-modal-button-close"
            >
              <svg width="14" height="14">
                <path d="M14 12.461 8.3 6.772l5.234-5.233L12.006 0 6.772 5.234 1.54 0 0 1.539l5.234 5.233L0 12.006l1.539 1.528L6.772 8.3l5.69 5.7L14 12.461z" />
              </svg>
            </button>
            {renderContent()}
          </div>
        </div>
        <div
          className="wallet-adapter-modal-overlay"
          onMouseDown={handleClose}
        />
      </div>,
      portal,
    )
  );
};
