import React from "react";
import keyBoardShortCut from "./utils/keyBoardShortCut";
import FocusVisible from "./utils/focusVisibleContext";
import Box from "../layout/Box";
import propTypes, { defaultPropTypes, propsDescription } from "./AccessibilityControl.propTypes";
import styles from "./AccessibilityControl.module.css";
import componentCategories from "../../docs-utils/componentCategories";
import componentGroups from "../../docs-utils/componentGroups";
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() {
    let ele = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
    let handleType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "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 {
      customStyle = {}
    } = this.props;
    let {
      focuscss = styles.focusVisible
    } = customStyle;
    let customFocusCss = el.getAttribute("data-aria-focusstyle");
    let getAccessibilityRoot = el.closest("[data-accessibility-root]");

    if (el.hasAttribute("data-focus-added")) {
      return;
    }

    if (customFocusCss) {
      el.classList.add(customFocusCss);
    } else {
      if (getAccessibilityRoot) {
        el.classList.add(getAccessibilityRoot.dataset.accessibilityRoot);
      } else {
        el.classList.add(focuscss);
      }
    }

    el.setAttribute("data-focus-added", "");
  }

  removeFocusVisibleClass(el) {
    let {
      customStyle = {}
    } = this.props;
    let {
      focuscss = styles.focusVisible
    } = customStyle;
    let customFocusCss = el.getAttribute("data-aria-focusstyle");
    let getAccessibilityRoot = el.closest("[data-accessibility-root]");

    if (!el.hasAttribute("data-focus-added")) {
      return;
    }

    if (customFocusCss) {
      el.classList.remove(customFocusCss);
    } else {
      if (getAccessibilityRoot) {
        el.classList.remove(getAccessibilityRoot.dataset.accessibilityRoot);
      } else {
        el.classList.remove(focuscss);
      }
    }

    el.removeAttribute("data-focus-added");
  }

  onKeyDown(e) {
    let {
      defaultAriaShortCut,
      customAriaShortCut
    } = 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);
  }

  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,
      customStyle = {},
      bindEvent,
      focusLoop,
      autoFocus
    } = this.props;
    let {
      hadKeyboardEvent
    } = this.state;
    let {
      box = "",
      focuscss
    } = customStyle;

    if (bindEvent == "document") {
      return /*#__PURE__*/React.createElement(FocusVisible.Provider, {
        value: {
          hadKeyboardEvent,
          isInitialized: true
        }
      }, /*#__PURE__*/React.createElement(React.Fragment, null, " ", children, " "));
    } else {
      return /*#__PURE__*/React.createElement(FocusVisible.Provider, {
        value: {
          hadKeyboardEvent,
          isInitialized: true
        }
      }, /*#__PURE__*/React.createElement(Box, {
        focusLoop: focusLoop,
        autoFocus: autoFocus,
        getRef: ele => {
          this.getEle = ele;
        },
        tagAttributeProps: {
          "data-accessibility-root": focuscss
        },
        className: styles.common + " " + box
      }, children));
    }
  }

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

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