import { fromEvent } from 'rxjs';
import {
  auditTime,
  throttleTime,
} from 'rxjs/operators';

import { ScrollStateType } from '../constants/type';

export const objIsEmpty = (obj: Object) => !Object.keys(obj).length;

export const watchScroll = (viewAreaElement: HTMLElement, cb: (state: ScrollStateType) => void) => {
  const debounceScroll = () => {
    if (rAF) {
      return;
    }
    // schedule an invocation of scroll for next animation frame.
    rAF = window.requestAnimationFrame(() => {
      rAF = null;

      let currentX = viewAreaElement.scrollLeft;
      let lastX = state.lastX;
      if (currentX !== lastX) {
        state.right = currentX > lastX;
      }
      state.lastX = currentX;
      let currentY = viewAreaElement.scrollTop;
      let lastY = state.lastY;
      if (currentY !== lastY) {
        state.down = currentY > lastY;
      }
      state.lastY = currentY;
      cb(state);
    });
  };

  let state = {
    right: true,
    down: true,
    lastX: viewAreaElement.scrollLeft,
    lastY: viewAreaElement.scrollTop,
  };
  let rAF: number | null = null;

  fromEvent(viewAreaElement, 'scroll').pipe(
    auditTime(300),
    throttleTime(200),
  ).subscribe(debounceScroll);

  return state;
};

export const scrollIntoView = (element: HTMLElement, spot?: {top: number}, skipOverflowHiddenElements: boolean = false) => {
  let parent: HTMLElement = <HTMLElement>element.offsetParent;
  let offsetY = element.offsetTop + element.clientTop;

  if (!parent) {
    return; // no need to scroll
  }
  while ((parent.clientHeight === parent.scrollHeight &&
          parent.clientWidth === parent.scrollWidth) ||
          (skipOverflowHiddenElements &&
          getComputedStyle(parent).overflow === 'hidden')) {
    if (parent.dataset._scaleY) {
      offsetY /= parseInt(parent.dataset._scaleY);
    }
    offsetY += parent.offsetTop;
    parent = <HTMLElement>parent.offsetParent;
    if (!parent) {
      return; // no need to scroll
    }
  }

  if (spot) {
    if (spot.top !== undefined) {
      offsetY += spot.top;
    }
  }

  parent.scrollTop = offsetY;
};

export const scaleCheck = (scale: number): number => {
  if (typeof scale === 'number' && scale >= 50 && scale <= 250) {
    return Math.round(scale * 100) / 10000;
  }
  if (scale < 50) {
    return 0.5;
  }
  return 2.5;
};
