import { computed, ref, watch, unref, watchEffect } from 'vue';
import { useResizeObserver, useEventListener } from '@vueuse/core';

// ts
import type { Table, TableProps, RenderExpanded } from './defaults';
import type TableLayout from '../table-layout';
import type { Store } from '../store';

function useStyle(
  props: TableProps,
  layout: TableLayout,
  store: Store,
  table: Table
) {
  // 滚动组件样式
  const scrollbarContentStyle = {
    display: 'inline-block',
    verticalAlign: 'middle',
  };

  // data

  // 拖动中
  const dragging = ref<boolean>(false);

  // 是否可以展开
  const renderExpanded = ref<RenderExpanded | null>(null);

  // 表格可滚动高度
  const tableScrollHeight = ref<number>(0);

  // 中间内容的高度
  const bodyScrollHeight = ref<number>(0);

  // 表格头部滚动高度
  const headerScrollHeight = ref<number>(0);

  // 表格底部滚动高度
  const footerScrollHeight = ref<number>(0);

  // 表格缩放
  const resizeState = ref<{
    width: null | number;
    height: null | number;
    headerHeight: null | number;
  }>({
    width: null,
    height: null,
    headerHeight: null,
  });

  // 表格宽度
  const tableWidth = ref<number>(0);

  // 是否拥有多级表头
  const isGroup = ref<boolean>(false);

  // computed

  // table-layout布局方式
  const tableLayout = computed(() => {
    // 有最大高度
    if (props.maxHeight) {
      return 'fixed';
    }

    return props.tableLayout;
  });

  // 内容样式
  const contentStyles = computed(() => {
    let obj = {};

    // 有固定高度
    if (props.height) {
      obj = {
        height: !Number.isNaN(Number(props.height))
          ? `${props.height}px`
          : props.height,
      };
    }

    // 有最大高度
    if (props.maxHeight) {
      obj = {
        maxHeight: !Number.isNaN(Number(props.maxHeight))
          ? `${props.maxHeight}px`
          : props.maxHeight,
      };
    }

    return obj;
  });

  // 表格内容宽度
  const tableStyles = computed(() => {
    const { scrollY, gutterWidth } = layout;

    return {
      width: layout.bodyWidth.value
        ? `${
            (layout.bodyWidth.value as number) -
            (scrollY.value ? gutterWidth : 0)
          }px`
        : '',
    };
  });

  // 高度是否有变化
  const shouldUpdateHeight = computed(() => {
    return (
      props.height ||
      props.maxHeight ||
      store.states.fixedColumns.value.length > 0 ||
      store.states.rightFixedColumns.value.length > 0
    );
  });

  // 提示样式
  const placeholderStyle = computed(() => {
    if (props.data && props.data.length) {
      return null;
    }

    let height = '100%';

    // 中间内容的高度
    if (props.height && bodyScrollHeight.value) {
      height = `${bodyScrollHeight.value}px`;
    }

    const width = tableWidth.value;

    return {
      width: width ? `${width}px` : '',
      height,
    };
  });

  // 内容宽度
  const tableBodyStyle = computed(() => {
    const { bodyWidth } = layout;

    const obj: any = {
      tableLayout: tableLayout.value,
    };

    if (bodyWidth.value) {
      obj.width = `${bodyWidth.value as number}px`;
    }

    return obj;
  });

  // 滚动组件样式
  const scrollbarWrapperStyle = computed(() => {
    // 有设置高度
    if (props.height) {
      return {
        height: '100%',
      };
    }

    // 有最大高度
    if (props.maxHeight) {
      // number
      if (!Number.isNaN(Number(props.maxHeight))) {
        const headerHeight = table.refs.header?.scrollHeight || 0;
        const maxHeight = props.maxHeight;

        // 超过最大高度
        const reachMaxHeight = tableScrollHeight.value >= Number(maxHeight);

        // 表格内容高度
        if (reachMaxHeight) {
          return {
            maxHeight: `${tableScrollHeight.value - headerHeight}px`,
          };
        }
      }
      // string
      else {
        return {
          maxHeight: `calc(${props.maxHeight} - ${headerScrollHeight.value}px)`,
        };
      }
    }

    return {};
  });

  // methods

  // 绑定事件
  const handleBindEvents = () => {
    const scrollbar = table.refs.scrollbar;

    // 没有滚动条
    if (!scrollbar) {
      return;
    }

    // 有滚动条
    if (scrollbar.scrollbarWrapper) {
      useEventListener(
        scrollbar.scrollbarWrapper,
        'scroll',
        handleScrollbarScroll,
        {
          passive: true,
        }
      );
    }

    // 列的宽度自撑开
    if (props.fit) {
      // 绑定resize
      useResizeObserver(table.vnode.el as HTMLElement, handleResizeListener);
    }
    // 表格大小改变
    else {
      useEventListener(window, 'resize', handleResizeListener);
    }
  };

  // 鼠标离开
  const handleMouseLeave = () => {
    // 清除列hover
    table.store.commit('setHoverRow', null);

    // 清除列hover
    if (table.hoverState) {
      table.hoverState = null;
    }
  };

  // 鼠标滚轮
  const handleMousewheel = (event, data) => {
    const { pixelX, pixelY } = data;

    // x 大于 y table横向滚动
    if (Math.abs(pixelX) >= Math.abs(pixelY)) {
      table.refs.bodyWrapper.scrollLeft += data.pixelX / 5;
    }
  };

  // 拖拽显示
  const handleDragVisible = (visible: boolean) => {
    dragging.value = visible;
  };

  // 更新布局
  const updateLayout = () => {
    // 高度是否有变化更新高度
    if (shouldUpdateHeight.value) {
      layout.updateTableContentHeight();
    }

    // 更新列的宽度
    layout.updateColumnsWidth();

    // 滚动条滚动
    requestAnimationFrame(handleScrollbarScroll);
  };

  // 表格大小改变
  const handleResizeListener = () => {
    // 表格是否渲染完成
    if (!table.$ready) {
      return;
    }

    // 更新布局
    let shouldUpdateLayout = false;

    // 当前el
    const el = table.vnode.el!;

    // 当前改变的值
    const {
      width: oldWidth,
      height: oldHeight,
      headerHeight: oldHeaderHeight,
    } = resizeState.value;

    // 当前表格宽度
    const width = (tableWidth.value = el.offsetWidth);

    // 有改变表格宽度
    if (oldWidth !== width) {
      shouldUpdateLayout = true;
    }

    // 监听高度变化
    const height = el.offsetHeight;
    if ((props.height || shouldUpdateHeight.value) && oldHeight !== height) {
      shouldUpdateLayout = true;
    }

    // 监听表格头部是否显示
    const tableHeader: HTMLElement = table.refs.header || {};

    if (
      tableHeader &&
      props.showHeader &&
      tableHeader.offsetHeight !== oldHeaderHeight
    ) {
      shouldUpdateLayout = true;
    }

    // 表格可滚动高度
    tableScrollHeight.value = table.refs.tableWrapper.scrollHeight;

    // 表格头部滚动高度
    headerScrollHeight.value = table.refs.header?.scrollHeight || 0;

    // 表格底部滚动高度
    footerScrollHeight.value = table.refs.footer?.scrollHeight || 0;

    // 中间内容的高度 = 表格可滚动高度 - 表格头部滚动高度 - 表格底部滚动高度
    bodyScrollHeight.value =
      tableScrollHeight.value -
      headerScrollHeight.value -
      footerScrollHeight.value;

    if (shouldUpdateLayout) {
      resizeState.value = {
        width,
        height,
        headerHeight: props.showHeader ? tableHeader.offsetHeight : null,
      };

      // 更新布局
      updateLayout();
    }
  };

  // 滚动条滚动
  const handleScrollbarScroll = () => {
    const scrollbar = table.refs.scrollbar;

    // 没有滚动
    if (!scrollbar) {
      return;
    }

    // 是否可以滚动
    if (!layout.scrollX.value) {
      const scrollingNoneClass = 'is-scrolling-none';

      if (!hasClass(scrollingNoneClass)) {
        setTableClass(scrollingNoneClass);
      }
    }

    const scrollContainer = scrollbar.scrollbarWrapper;

    // 没有滚动条
    if (!scrollContainer) {
      return;
    }

    const { scrollLeft, offsetWidth, scrollWidth } = scrollContainer;
    const { header, footer } = table.refs;

    // 设置头部滚动位置
    if (header) {
      header.scrollLeft = scrollLeft;
    }

    // 设置底部滚动位置
    if (footer) {
      footer.scrollLeft = scrollLeft;
    }

    // 最大滚动位置
    const maxScrollLeftPosition = scrollWidth - offsetWidth - 1;

    // 最右边
    if (scrollLeft >= maxScrollLeftPosition) {
      setTableClass('is-scrolling-right');
    }
    // 滚动到最左边
    else if (scrollLeft === 0) {
      setTableClass('is-scrolling-left');
    }
    // 滚动到中间
    else {
      setTableClass('is-scrolling-middle');
    }
  };

  // 是否有当前样式
  const hasClass = (className: string) => {
    const { tableWrapper } = table.refs;

    return !!(tableWrapper && tableWrapper.classList.contains(className));
  };

  // 设置表格样式
  const setTableClass = (className: string) => {
    const { tableWrapper } = table.refs;

    if (!tableWrapper) {
      return;
    }

    const classList = Array.from(tableWrapper.classList).filter(
      (item) => !item.startsWith('is-scrolling-')
    );

    classList.push(layout.scrollX.value ? className : 'is-scrolling-none');

    tableWrapper.className = classList.join(' ');
  };

  // 监听数据变化
  watch(
    () => props.data,
    (data) => {
      table.store.commit('setData', data);
    },
    {
      immediate: true,
      deep: true,
    }
  );

  // 监听行key
  watch(
    () => [store.states.rowKey],
    ([currentRowKey, rowKey]) => {
      if (!unref(rowKey)) {
        return;
      }

      // 设置当前行的key
      store.setCurrentRowKey(`${currentRowKey}`);
    },
    {
      immediate: true,
    }
  );

  // watchEffect

  // 监听高度变化设置表格高度
  watchEffect(() => {
    props.height && layout.setHeight(props.height);
  });

  // 监听高度变化设置表格最大高度
  watchEffect(() => {
    props.maxHeight && layout.setMaxHeight(props.maxHeight);
  });

  // 以通过该属性设置 Table 目前的展开行
  watchEffect(() => {
    if (props.expandRowKeys) {
      store.setExpandRowKeysAdapter(props.expandRowKeys);
    }
  });

  return {
    // data
    dragging,
    renderExpanded,
    resizeState,
    tableWidth,
    isGroup,

    // computed
    tableLayout,
    contentStyles,
    tableStyles,
    placeholderStyle,
    tableBodyStyle,
    scrollbarWrapperStyle,
    scrollbarContentStyle,

    // methods
    handleMouseLeave,
    handleMousewheel,
    handleDragVisible,
    updateLayout,
    handleBindEvents,
  };
}

export default useStyle;
