import { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil';

import { collectionStore } from '../../stores';
import { deletePlaylistFromWNFS, type Playlist } from '../../lib/playlists';
import { ipfsGatewayUrl } from '../../../../lib/app-info';
import Download from '../../../../components/icons/Download';
import Trash from '../../../../components/icons/Trash';

type Props = {
  playlist: Playlist;
  isModalOpen: boolean;
  onClose: () => void;
};

const PlaylistModal = ({ playlist, isModalOpen, onClose }: Props) => {
  const collection = useRecoilValue(collectionStore);
  const [selectedPlaylist, setSelectedPlaylist] = useState<Playlist | null>(
    playlist
  );
  const [openModal, setOpenModal] = useState<boolean>(isModalOpen);
  const [previousPlaylist, setPreviousPlaylist] = useState<Playlist | null>();
  const [nextPlaylist, setNextPlaylist] = useState<Playlist | null>();
  const [showPreviousArrow, setShowPreviousArrow] = useState<boolean>();
  const [showNextArrow, setShowNextArrow] = useState<boolean>();

  /**
   * Close the modal, clear the playlist state vars, set `isModalOpen` to false
   * and dispatch the close event to clear the playlist from the parent's state
   */
  const handleCloseModal: () => void = () => {
    setPreviousPlaylist(null);
    setNextPlaylist(null);
    setSelectedPlaylist(null);
    setOpenModal(false);
    onClose();
  };

  /**
   * Delete an playlist from the user's WNFS
   */
  const handleDeletePlaylist: () => Promise<void> = async () => {
    if (selectedPlaylist) {
      await deletePlaylistFromWNFS(selectedPlaylist.name);
      handleCloseModal();
    }
  };

  /**
   * Set the previous and next playlists to be toggled to when the arrows are clicked
   */
  const setCarouselState = () => {
    const playlistList = selectedPlaylist?.private
      ? collection.privatePlaylists
      : collection.publicPlaylists;
    const currentIndex = playlistList.findIndex(
      (val) => val.cid === selectedPlaylist?.cid
    );
    const updatedPreviousPlaylist =
      playlistList[currentIndex - 1] ?? playlistList[playlistList.length - 1];
    setPreviousPlaylist(updatedPreviousPlaylist);
    const updatedNextPlaylist =
      playlistList[currentIndex + 1] ?? playlistList[0];
    setNextPlaylist(updatedNextPlaylist);

    setShowPreviousArrow(playlistList.length > 1 && !!updatedPreviousPlaylist);
    setShowNextArrow(playlistList.length > 1 && !!updatedNextPlaylist);
  };

  /**
   * Load the correct playlist when a user clicks the Next or Previous arrows
   * @param direction
   */
  const handleNextOrPrevPlaylist: (direction: 'next' | 'prev') => void = (
    direction
  ) => {
    setSelectedPlaylist(
      (direction === 'prev' ? previousPlaylist : nextPlaylist) ?? null
    );
  };
  useEffect(() => {
    setCarouselState();
  }, [selectedPlaylist]);

  /**
   * Detect `Escape` key presses to close the modal or `ArrowRight`/`ArrowLeft`
   * presses to navigate the carousel
   * @param event
   */
  const handleKeyDown: (event: KeyboardEvent) => void = (event) => {
    if (event.key === 'Escape') handleCloseModal();

    if (showNextArrow && event.key === 'ArrowRight')
      handleNextOrPrevPlaylist('next');

    if (showPreviousArrow && event.key === 'ArrowLeft')
      handleNextOrPrevPlaylist('prev');
  };

  // Attach attach left/right/esc keys to modal actions
  useEffect(() => {
    window.addEventListener('keydown', handleKeyDown);

    return () => {
      window.removeEventListener('keydown', handleKeyDown);
    };
  }, [handleKeyDown]);

  const useMountEffect = () =>
    useEffect(() => {
      setCarouselState();
    }, []);

  useMountEffect();

  if (selectedPlaylist) {
    return (
      <>
        <input
          type="checkbox"
          id={`playlist-modal-${selectedPlaylist.cid}`}
          className="modal-toggle"
          checked={openModal}
          onChange={() => undefined}
        />
        <label
          htmlFor={`playlist-modal-${selectedPlaylist.cid}`}
          className="z-50 cursor-pointer modal"
          onClick={(event) => {
            if (event.currentTarget !== event.target) {
              return;
            }

            handleCloseModal();
          }}
        >
          <div className="relative text-center modal-box text-base-content">
            <label
              htmlFor={`playlist-modal-${selectedPlaylist.cid}`}
              className="absolute btn btn-xs btn-circle right-2 top-2"
              onClick={handleCloseModal}
            >
              ✕
            </label>
            <div>
              <h3 className="text-lg break-all mb-7">
                {selectedPlaylist.name}
              </h3>

              <div className="relative">
                {showPreviousArrow && (
                  <button
                    className="absolute top-1/2 -left-[25px] -translate-y-1/2 inline-block text-center text-[40px]"
                    onClick={() => handleNextOrPrevPlaylist('prev')}
                  >
                    &#8249;
                  </button>
                )}
                <img
                  className="block object-cover object-center border-2 border-base-content w-full h-full mb-4 rounded-[1rem]"
                  alt={selectedPlaylist.name}
                  src={selectedPlaylist.src}
                />
                {showNextArrow && (
                  <button
                    className="absolute top-1/2 -right-[25px] -translate-y-1/2 inline-block text-center text-[40px]"
                    onClick={() => handleNextOrPrevPlaylist('next')}
                  >
                    &#8250;
                  </button>
                )}
              </div>
              <div className="flex flex-col items-center justify-center">
                <p className="mb-2 text-neutral-500">
                  Created {new Date(selectedPlaylist.ctime).toDateString()}
                </p>

                <a
                  href={`https://ipfs.${ipfsGatewayUrl}/ipfs/${selectedPlaylist.cid}/userland`}
                  target="_blank"
                  rel="noreferrer"
                  className="mb-2 underline hover:text-neutral-500"
                >
                  View on IPFS{selectedPlaylist.private && `*`}
                </a>

                {selectedPlaylist.private && (
                  <>
                    <p className="mb-2 text-neutral-700 dark:text-neutral-500">
                      * Your private files can only be viewed on devices that
                      have permission. When viewed directly on IPFS, you will
                      see the encrypted state of this file. This is because the
                      raw IPFS gateway view does not have permission to decrypt
                      this file.
                    </p>
                    <p className="mb-2 text-neutral-700 dark:text-neutral-500">
                      Interested in private file sharing as a feature? Follow
                      the{' '}
                      <a
                        className="underline"
                        href="https://github.com/oddsdk/odd-app-template/issues/4"
                        target="_blank"
                        rel="noreferrer"
                      >
                        github issue.
                      </a>
                    </p>
                  </>
                )}

                <div className="flex flex-col items-center justify-between gap-4 mt-4 sm:flex-row">
                  <a
                    href={selectedPlaylist.src}
                    download={selectedPlaylist.name}
                    className="gap-2 btn btn-primary"
                  >
                    <Download />
                    Download Playlist
                  </a>
                  <button
                    className="gap-2 btn btn-outline"
                    onClick={handleDeletePlaylist}
                  >
                    <Trash />
                    Delete Playlist
                  </button>
                </div>
              </div>
            </div>
          </div>
        </label>
      </>
    );
  }

  return null;
};

export default PlaylistModal;