// 把 TableLayout 的 useDetectOverflow 迁移到这里，主要是因为这个逻辑目前也是为了修复 ATable 的，放在 TableLayout 不太合适
// 可以省去几个 provide/inject 逻辑
// 仅当表格开了 :scroll="{y: xxx}" 启动这个逻辑
import { nextTick, onUnmounted, ref, onMounted, watch, type Ref } from 'vue';
import ResizeObserver from 'resize-observer-polyfill';
import { type MyHTMLElement } from '../types/index';
const ANT_TABLE_BODY_CLS_NAME = 'ant-table-body';
export const useDetectOverflow = ({
  tableCls,
  enabled
}: {
  tableCls: string;
  enabled: Ref<boolean>;
}) => {
  // ⚠ ⚠ ⚠ 初始化需要为 undefined
  const hasScrollbar = ref<boolean>();
  let roHasScrollbar: ResizeObserver | null = null;

  // 销毁 roHasScrollbar
  const destroyObserver = () => {
    if (roHasScrollbar) {
      roHasScrollbar.disconnect();
      roHasScrollbar = null;
    }
    hasScrollbar.value = undefined;
  };

  const registerObserver = () => {
    if (enabled.value) {
      const tableRef: { value: MyHTMLElement } = {
        value: document.querySelector(`.${tableCls}`)
      };
      if (tableRef.value) {
        let tableBodyEl: MyHTMLElement;
        const getTableBodyEl = (tableRef: { value: MyHTMLElement }) => {
          if (tableBodyEl) return tableBodyEl;
          tableBodyEl = tableRef.value?.querySelector(
            `.${ANT_TABLE_BODY_CLS_NAME}`
          ) as MyHTMLElement;
          return tableBodyEl;
        };
        // 监听是否 table body 是否有滚动条
        roHasScrollbar = new ResizeObserver(
          debounce(entries => {
            const entry = entries[0];
            if (entry.target.scrollHeight > entry.target.clientHeight) {
              console.log(
                `[antd-table] ${tableRef.value} table body 出现滚动条 ✅`
              );
              // ✨ 处理 antd 针对表头的 scrollbar 的计算，这个值会传递到 antd 底层 Table 的 FixedHolder 组件（需要 patch-package 修复）
              hasScrollbar.value = true;
            } else {
              console.log(
                `[antd-table] ${tableRef.value} table body 没有出现滚动条 ❌`
              );
              hasScrollbar.value = false;
            }
          }, 100)
        );
        tableBodyEl = getTableBodyEl(tableRef);
        roHasScrollbar.observe(tableBodyEl as Element);
      }
    } else {
      destroyObserver();
    }
  };
  onMounted(async () => {
    await nextTick();
    registerObserver();
  });
  onUnmounted(() => {
    roHasScrollbar?.disconnect();
    roHasScrollbar = null;
  });
  watch(enabled, registerObserver, { flush: 'post' });
  return { hasScrollbar };
};

function throttle<T extends (...args: any[]) => void>(
  func: T,
  delay: number
): (...args: Parameters<T>) => void {
  let waiting = false;
  return function (this: ThisParameterType<T>, ...args: Parameters<T>): void {
    if (!waiting) {
      func.apply(this, args);
      waiting = true;
      setTimeout(() => {
        waiting = false;
      }, delay);
    }
  };
}

function debounce<T extends (...args: any[]) => void>(
  func: T,
  delay: number
): (...args: Parameters<T>) => void {
  let timer: number;
  return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
    clearTimeout(timer);
    timer = window.setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };
}
