import React from "react";
import keyBoardShortCut from "../../accessibility-utils/keyBoardShortCut";
import arrowNavigate from "../../accessibility-utils/keyNavigator";
import Box from "../layout/Box";
import propTypes, {
  defaultPropTypes,
  propsDescription
} from "./AccessibilityControl.propTypes.js";
import styles from "./AccessibilityControl.module.css";
import componentCategories from "../../docs-utils/componentCategories";
import componentGroups from "../../docs-utils/componentGroups";
import FocusVisible from "../../accessibility-utils/focusVisibleContext";

export default class AccessibilityControl extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hadKeyboardEvent: true };
    this.isValidFocusTarget = this.isValidFocusTarget.bind(this);
    this.addFocusVisibleClass = this.addFocusVisibleClass.bind(this);
    this.removeFocusVisibleClass = this.removeFocusVisibleClass.bind(this);
    this.onKeyDown = this.onKeyDown.bind(this);
    this.onPointerDown = this.onPointerDown.bind(this);
    this.onFocus = this.onFocus.bind(this);
    this.onBlur = this.onBlur.bind(this);
    this.handleEventListner = this.handleEventListner.bind(this);
    this.getEle = null;
  }

  handleEventListner(ele = null, handleType = "addEventListener") {
    let eventDetails = [
      { name: "keydown", functionName: "onKeyDown" },
      { name: "mousedown", functionName: "onPointerDown" },
      { name: "pointerdown", functionName: "onPointerDown" },
      { name: "touchstart", functionName: "onPointerDown" },
      { name: "focus", functionName: "onFocus" },
      { name: "blur", functionName: "onBlur" }
    ];
    eventDetails.forEach((eventDetail, i) => {
      let { name, functionName } = eventDetail;
      if (ele) {
        ele[handleType](name, this[functionName], true);
      }
    });
  }

  componentDidMount() {
    let { bindEvent } = this.props;
    let handleEvent = bindEvent == "document" ? document : this.getEle;
    this.handleEventListner(handleEvent, "addEventListener");
  }

  componentWillUnmount() {
    let { bindEvent } = this.props;
    let handleEvent = bindEvent == "document" ? document : this.getEle;
    this.handleEventListner(handleEvent, "removeEventListener");
    this.removeFocusVisibleClass(document.activeElement);
  }

  isValidFocusTarget(el) {
    if (
      el &&
      el !== document &&
      el.nodeName !== "HTML" &&
      el.nodeName !== "BODY" &&
      "classList" in el &&
      "contains" in el.classList &&
      document.activeElement.dataset.accessibilityRoot !== "true"
    ) {
      return true;
    }
    return false;
  }

  addFocusVisibleClass(el) {
    let { customClassName = {} } = this.props;
    let { focuscss = styles.focusVisible } = customClassName;
    let customFocusCss = el.getAttribute("data-aria-focusstyle");
    if (el.hasAttribute("data-focus-added")) {
      return;
    }
    if (customFocusCss) {
      el.classList.add(customFocusCss);
    } else {
      el.classList.add(focuscss);
    }
    el.setAttribute("data-focus-added", "");
  }

  removeFocusVisibleClass(el) {
    let { customClassName = {} } = this.props;
    let { focuscss = styles.focusVisible } = customClassName;
    let customFocusCss = el.getAttribute("data-aria-focusstyle");
    if (!el.hasAttribute("data-focus-added")) {
      return;
    }
    if (customFocusCss) {
      el.classList.remove(customFocusCss);
    } else {
      el.classList.remove(focuscss);
    }
    el.removeAttribute("data-focus-added");
  }

  onKeyDown(e) {
    let { defaultAriaShortCut, customAriaShortCut, isKeyNavigation } =
      this.props;
    let currentActiveEle = document.activeElement;
    if (e.metaKey || e.altKey || e.ctrlKey) {
      return;
    }
    if (this.isValidFocusTarget(currentActiveEle)) {
      this.addFocusVisibleClass(currentActiveEle);
    }
    this.setState({ hadKeyboardEvent: true });

    keyBoardShortCut(
      e,
      currentActiveEle,
      defaultAriaShortCut,
      customAriaShortCut
    );
    isKeyNavigation && arrowNavigate(e, currentActiveEle);
  }

  onPointerDown(e) {
    this.setState({ hadKeyboardEvent: false });
    this.removeFocusVisibleClass(e.target);
  }

  onFocus(e) {
    if (!this.isValidFocusTarget(e.target)) {
      return;
    }
    if (this.state.hadKeyboardEvent) {
      this.addFocusVisibleClass(e.target);
    }
  }

  onBlur(e) {
    if (!this.isValidFocusTarget(e.target)) {
      return;
    }
    if (e.target.hasAttribute("data-focus-added")) {
      this.removeFocusVisibleClass(e.target);
    }
  }

  render() {
    let {
      children,
      customClassName = {},
      bindEvent,
      focusLoop,
      autoFocus
    } = this.props;
    let {
      hadKeyboardEvent
    } = this.state;
    let { box = "" } = customClassName;
    if (bindEvent == "document") {
      return(
        <FocusVisible.Provider value={{ hadKeyboardEvent,isInitialized:true }}>
          <React.Fragment> {children} </React.Fragment>
        </FocusVisible.Provider>
      ) 
    } else {
      return (
        <FocusVisible.Provider value={{ hadKeyboardEvent,isInitialized:true }}>
          <Box
            focusLoop={focusLoop}
            autoFocus={autoFocus}
            eleRef={(ele) => {
              this.getEle = ele;
            }}
            data-accessibility-root
            className={styles.common + " " + box}
          >
           
            {children}
          </Box>
        </FocusVisible.Provider>
      );
    }
  }
}

AccessibilityControl.propTypes = propTypes;
AccessibilityControl.defaultProps = defaultPropTypes;
AccessibilityControl.propsDescription = propsDescription;

if (__DOCS__) {
  AccessibilityControl.docs = {
    componentGroup: componentGroups.Components,
    folderName: componentCategories.Accessibility
  };
}
