import { easeInOutCubic } from "./easing.mjs";
import { throttleRAF } from "./helper.mjs";
import { isWindow, isArray, isFunction } from "./is.mjs";
function isDocument(val) {
  return val instanceof Document || (val == null ? void 0 : val.constructor.name) === "HTMLDocument";
}
function isHtmlElement(el) {
  if (typeof HTMLElement === "object") {
    return el instanceof HTMLElement;
  } else if (el && typeof el === "object") {
    const ele = el;
    return (ele.nodeType === 1 || ele.nodeType === 9) && typeof ele.nodeName === "string";
  }
  return false;
}
function getOffsetElement(el) {
  const offsetEl = el.offsetParent;
  if (offsetEl && offsetEl.tagName === "BODY") {
    const stylePosition = window.getComputedStyle(document.body).getPropertyValue("position");
    if (stylePosition === "static") {
      return document.documentElement;
    }
  }
  return offsetEl;
}
function getScroll(el) {
  const rlt = {
    scrollLeft: 0,
    scrollTop: 0
  };
  if (!el) {
    return rlt;
  }
  if (isWindow(el)) {
    rlt.scrollLeft = window.scrollX;
    rlt.scrollTop = window.scrollY;
  } else if (isDocument(el)) {
    rlt.scrollLeft = el.documentElement.scrollLeft;
    rlt.scrollTop = el.documentElement.scrollTop;
  } else {
    rlt.scrollLeft = el.scrollLeft;
    rlt.scrollTop = el.scrollTop;
  }
  return rlt;
}
function getScrollParents(el) {
  const parents = [];
  let ele = el;
  while (ele && ele !== document.documentElement) {
    const { offsetHeight, offsetWidth, scrollHeight, scrollWidth } = ele;
    if (offsetHeight < scrollHeight || offsetWidth < scrollWidth) {
      parents.push(ele);
    }
    ele = ele.parentElement;
  }
  return parents;
}
function getElementSize(el) {
  return {
    width: el.innerWidth || el.clientWidth,
    height: el.innerHeight || el.clientHeight,
    offsetWidth: el.innerWidth || el.offsetWidth,
    offsetHeight: el.innerHeight || el.offsetHeight
  };
}
function getElementBorder(el, dir) {
  const style = window.getComputedStyle(el);
  let d = [];
  {
    d = isArray(dir) ? dir : ["left", "right", "bottom", "top"];
  }
  const rlt = {};
  d.forEach((k) => {
    rlt[k] = parseFloat(style.getPropertyValue(`border-${k}-width`));
  });
  return rlt;
}
function supportTouch() {
  return "ontouchstart" in window;
}
function mergeClass(...classList) {
  let rlt = [];
  classList.forEach((item) => {
    if (isArray(item)) {
      rlt = rlt.concat(item);
    } else {
      rlt.push(item);
    }
  });
  return rlt;
}
let cancelScrollRAF = null;
function scrollTo(y, opts) {
  const { container = window, duration = 450 } = opts;
  const { scrollTop } = getScroll(container);
  const startTime = Date.now();
  if (isFunction(cancelScrollRAF)) {
    cancelScrollRAF();
    cancelScrollRAF = null;
  }
  return new Promise((resolve) => {
    const frameFn = () => {
      const timeStamp = Date.now();
      const time = timeStamp - startTime;
      const nextScrollTop = easeInOutCubic(time > duration ? duration : time, scrollTop, y, duration);
      if (isWindow(container)) {
        window.scrollTo({
          left: window.scrollX,
          top: nextScrollTop,
          behavior: "instant"
        });
      } else if (isDocument(container)) {
        container.documentElement.scrollTop = nextScrollTop;
      } else {
        container.scrollTop = nextScrollTop;
      }
      if (time < duration) {
        const fn = throttleRAF(frameFn);
        cancelScrollRAF = fn.cancel;
        fn();
      } else {
        throttleRAF(resolve)();
      }
    };
    throttleRAF(frameFn)();
  });
}
function isOverflown(element) {
  if (!element) {
    return false;
  }
  return element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight;
}
export {
  getElementBorder,
  getElementSize,
  getOffsetElement,
  getScroll,
  getScrollParents,
  isDocument,
  isHtmlElement,
  isOverflown,
  mergeClass,
  scrollTo,
  supportTouch
};
