import React, { useEffect } from 'react';
import styled from 'styled-components';

import v from '../../styles/Variables';
import trapFocus from '../../utils/TrapFocus';
import Close from '../NavButton/Close';
interface Props {
  /**
   * the color of the mask
   */
  backgroundColor?: string;
  /**
   * any valid jsx
   */
  children: React.ReactNode;
  /**
   * function to happen after the back button is clicked
   */
  backCb: () => void;
  /**
   * function to happen after the close button is clicked
   */
  closeCb: () => void;
  /**
   * if the drawer is currently open or not
   */
  drawerOpen: boolean;
  /**
   * id added to the main wrapper
   */
  id?: string;
  /**
   * class applied to the drawer
   */
  theme?: string;
  /**
   * docked on the right if true
   */
  onRight?: boolean;
  /**
   * the page behind will not scroll when enabled
   */
  preventScroll?: boolean;
  /**
   * show the back button
   */
  showBack?: boolean;
  /**
   * show the close button
   */
  showClose?: boolean;
  /**
   * allow swiping to close
   */
  swipeToClose?: boolean;
  /**
   * title of the drawer
   */
  title?: string;
}

interface Styles {
  backgroundColor: string;
}

const Drawer = ({
  backgroundColor = v.colors.light,
  children,
  backCb,
  closeCb,
  drawerOpen = false,
  id = 'my-drawer-id',
  theme,
  onRight = false,
  preventScroll = true,
  showBack = false,
  showClose = true,
  swipeToClose,
  title,
}: Props) => {
  // change docked position
  let positionStyle = {};
  if (onRight === true) positionStyle = { left: 'inherit', right: 0 };

  useEffect(() => {
    document.addEventListener('keydown', (e) => {
      trapFocus(e, id, drawerOpen);

      if (e.key === 'Escape') {
        window.document.getElementsByTagName('html')[0].classList.remove('nwc--noscroll');
        closeCb();
      }
    });
  }, []);

  // stop the body from being scrollable
  useEffect(() => {
    const elClassList = window.document.getElementsByTagName('html')[0].classList;

    setTimeout(() => {
      if (window.document && preventScroll === true && drawerOpen === true) {
        if (elClassList.contains('nwc--noscroll')) {
          elClassList.remove('nwc--noscroll');
        } else {
          elClassList.add('nwc--noscroll');
        }
      }

      // if open, focus the close button for accessibility
      const closeBtn = document.querySelector<HTMLElement>('.nwc--drawer .nwc--hamburger');
      if (drawerOpen === true) closeBtn!.focus();
    }, 300);
  }, [drawerOpen, preventScroll]);

  // swipe detection :: https://stackoverflow.com/questions/2264072/detect-a-finger-swipe-through-javascript-on-the-iphone-and-android
  if (swipeToClose === true && drawerOpen) {
    document.addEventListener('touchstart', handleTouchStart, false);
    document.addEventListener('touchmove', handleTouchMove, false);
  }

  let xDown: number | null = null;
  let yDown: number | null = null;

  function getTouches(e: TouchEvent) {
    return e.touches;
  }

  function handleTouchStart(e: TouchEvent) {
    const firstTouch = getTouches(e)[0];
    xDown = firstTouch.clientX;
    yDown = firstTouch.clientY;
    console.log('handleTouchStart');
  }

  function handleTouchMove(evt: TouchEvent) {
    if (!xDown || !yDown || drawerOpen !== true) return;

    let xUp = evt.touches[0].clientX;
    let yUp = evt.touches[0].clientY;

    var xDiff = xDown - xUp;
    var yDiff = yDown - yUp;

    if (Math.abs(xDiff) > Math.abs(yDiff)) {
      if (xDiff > 0) {
        // left swipe
        // console.log('left');
        if (onRight !== true) {
          window.document.getElementsByTagName('html')[0].classList.remove('nwc--noscroll');
          closeCb();
        }
      } else {
        // right swipe
        // console.log('right');
        if (onRight === true) {
          window.document.getElementsByTagName('html')[0].classList.remove('nwc--noscroll');
          closeCb();
        }
      }
    } else {
      if (yDiff > 0) {
        console.log('up'); // up swipe
      } else {
        console.log('down'); // down swipe
      }
    }

    // reset values
    xDown = null;
    yDown = null;
  }

  return (
    <DrawerStyles
      id={id}
      data-test="component-drawer"
      className={drawerOpen === true ? `nwc--drawer ${theme}` : `nwc--drawer closed ${theme}`}
      backgroundColor={backgroundColor}
      style={{
        ...positionStyle,
      }}
      aria-hidden={drawerOpen !== true ? 'true' : 'false'}
      role="dialog"
      aria-modal="true"
      aria-label={title}
    >
      <nav className="drawer--wrapper">
        <section data-test="component-drawer-wrapper">
          {showBack === true && (
            <BackStyles onClick={() => backCb()}>
              <i className="fal fa-chevron-left font--24" />
            </BackStyles>
          )}

          <Title>
            {showBack === true && <span>&nbsp;&nbsp;&nbsp;</span>}
            <span>{title}</span>
          </Title>
          <h2 className="sr-only">{title}</h2>
          {showClose === true && (
            <Close
              callback={() => {
                window.document.getElementsByTagName('html')[0].classList.remove('nwc--noscroll');
                closeCb();
              }}
            />
          )}
          {children}
        </section>
      </nav>
      <Mask className="nwc--drawer-mask" onClick={() => closeCb()} />
    </DrawerStyles>
  );
};

export default Drawer;

/* styles */
const DrawerStyles = styled.div<Styles>`
  opacity: 1;
  position: fixed;
  height: 100%;
  width: 90%;
  max-width: 380px;
  top: 0;
  left: 0;
  transition: all 0.2s linear;
  z-index: 9999;

  &.closed {
    left: -1000px;
  }
  .drawer--wrapper {
    position: relative;
    height: 100%;
    width: 100%;
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.3);
    background: ${({ backgroundColor }) => backgroundColor};
    overflow-y: scroll;
    z-index: 999;
  }

  .nwc--hamburger {
    position: absolute;
    right: 5px;
    top: 5px;
  }
`;

const Mask = styled.aside`
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 99;
  background: rgba(0, 0, 0, 0.66);
`;

const Title = styled.div`
  line-height: 60px;
  font-size: 21px;
  padding-left: 10px;
  color: ${v.colors.dark};
`;

const BackStyles = styled.span`
  position: absolute;
  left: 5px;
  top: 5px;
  width: 40px;
  height: 40px;
  line-height: 57px;
`;
