import { Table, TableProps } from "antd";
import React, { useLayoutEffect, useRef, useState } from "react";
import { ReactComponent as Loading } from "./loader.svg";
import "./Table.scss";
import useObserverWithRefCallback from "./../../hooks/useObserverWithRefCallback";
import { DEFAULT_TABLE_HEADER_HEIGHT } from "../../utils/constants";
import { useDebouncedWindowSize } from "../../hooks/useDebouncedWindowSize";
import { ReactComponent as Lefticon } from "./left.svg";
import { ReactComponent as RightIcon } from "./right.svg";
import { debounce } from "../../utils/utils";

type Props = {
  loading?: boolean;
  infiniteScrollConfig?: {
    callback: () => void;
    numberOfObserverSkippedFromLast?: number;
    hasMore?: boolean;
  };
  flexHeight?: boolean;
  horizontalScrollConfig?: {
    enable: boolean;
    threshold: number;
  };
};

const StarshipTable = <RecordType extends object = any>(
  props: TableProps<RecordType> & Props
) => {
  const {
    className,
    loading = false,
    dataSource,
    infiniteScrollConfig,
    onRow,
    flexHeight = false,
    scroll = {},
    horizontalScrollConfig = { enable: false, threshold: 10 },
    ...restProps
  } = props;

  const {
    callback,
    numberOfObserverSkippedFromLast = 0,
    hasMore = true,
  } = infiniteScrollConfig || {};
  const { enable: horizontalScrollEnabled, threshold } = horizontalScrollConfig;

  const [tableHeight, setTableHeight] = useState(0);
  const wrapperRef = useRef<HTMLDivElement>(null);
  const setRef = useObserverWithRefCallback(callback, hasMore);
  const dimensions = useDebouncedWindowSize({ activateListner: flexHeight });
  const antdTable = useRef<Element | null>(null);
  const [horizontalScrollLeft, setHorizontalScrollLeft] = useState(0);
  const [maxHorizontalScroll, setMaxHorizontalScroll] = useState(0);

  const onScrollArrow = (threshold: number = 0) => {
    if (antdTable.current) {
      //setting state of lefr scroll
      setHorizontalScrollLeft(antdTable.current.scrollLeft + threshold);

      //scrolling element
      antdTable.current.scroll({
        left: antdTable.current.scrollLeft + threshold,
      });
    }
  };

  const scrollCb = debounce(() => {
    if (antdTable.current)
      setHorizontalScrollLeft(antdTable.current.scrollLeft);
  }, 200);

  useLayoutEffect(() => {
    if (wrapperRef.current && flexHeight) {
      //handling table height
      const wrapperHeight = wrapperRef.current?.clientHeight;
      const tableHeaderHeight =
        wrapperRef.current.querySelector(".ant-table-header")?.clientHeight;
      const tableContentHeight = tableHeaderHeight
        ? wrapperHeight - tableHeaderHeight
        : wrapperHeight - DEFAULT_TABLE_HEADER_HEIGHT;
      setTableHeight(tableContentHeight);

      //handling horizontal scroll
      if (horizontalScrollEnabled) {
        antdTable.current = wrapperRef.current.querySelector(".ant-table-body");
        const antdScrollWidth = antdTable.current?.scrollWidth;
        const antdWidth = antdTable.current?.clientWidth;
        let antMaxHorizontalScroll = 0;
        if (antdScrollWidth && antdWidth) {
          antMaxHorizontalScroll = antdScrollWidth - antdWidth;
          setMaxHorizontalScroll(antMaxHorizontalScroll);
        }

        antdTable.current?.addEventListener("scroll", scrollCb);
      }
    }
    return () => {
      antdTable.current?.removeEventListener("scroll", scrollCb);
    };
  }, [wrapperRef.current, flexHeight, dimensions]);

  return (
    <div ref={wrapperRef} className="starship-table-wrapper">
      {horizontalScrollEnabled && maxHorizontalScroll > 0 && (
        <div className="slider">
          {horizontalScrollLeft > 0 && maxHorizontalScroll > 0 && (
            <div
              className="left arrow"
              onClick={() => onScrollArrow(-threshold)}
            >
              <div className="pointer">
                <Lefticon />
              </div>
            </div>
          )}
          {horizontalScrollLeft < maxHorizontalScroll && (
            <div
              className="right arrow"
              onClick={() => onScrollArrow(threshold)}
            >
              <div className="pointer">
                <RightIcon />
              </div>
            </div>
          )}
        </div>
      )}

      <Table
        {...restProps}
        dataSource={dataSource}
        className={`starship-table ${className}`}
        loading={loading && { indicator: <Loading /> }}
        onRow={
          onRow
            ? onRow
            : (_, index) => {
                //attaching ref to the last element to observe it
                if (
                  !loading &&
                  infiniteScrollConfig &&
                  dataSource &&
                  dataSource.length > 0
                ) {
                  if (
                    index ===
                    dataSource.length - 1 - numberOfObserverSkippedFromLast
                  ) {
                    return {
                      ref: setRef,
                    };
                  }
                }
                return {
                  className: "", //need to return set or props else showing TS warning
                };
              }
        }
        scroll={
          flexHeight && tableHeight !== 0
            ? { y: tableHeight, ...scroll }
            : scroll
        }
      />
    </div>
  );
};

export default StarshipTable;
