import { defineComponent, ref, computed, onMounted, watch, onBeforeUnmount, resolveComponent, openBlock, createElementBlock, normalizeClass, createElementVNode, normalizeStyle, renderSlot, Fragment, createVNode, createCommentVNode } from 'vue';
import getPrefixCls from '../_util/getPrefixCls';
import { useTheme } from '../_theme/useTheme';
import { pxfy, requestAnimationFrame } from '../_util/utils';
import useResize from '../_util/use/useResize';
import FBar from './bar.js';
import useScrollbar from './useScrollbar';
import { scrollbarProps } from './const';

const prefixCls = getPrefixCls('scrollbar');
var script = defineComponent({
  name: 'FScrollbar',
  components: {
    FBar
  },
  props: scrollbarProps,
  emits: ['scroll'],
  setup(props, _ref) {
    let {
      emit
    } = _ref;
    useTheme();
    const {
      onUpdate,
      onScroll,
      containerRef,
      ratioX,
      ratioY,
      thumbMoveX,
      thumbMoveY,
      sizeHeight,
      sizeWidth,
      scrollX,
      scrollXRatio,
      scrollY,
      scrollYRatio
    } = useScrollbar(props);
    const scrollbarRef = ref();
    const contentRef = ref();
    const shadowRef = computed(() => {
      if (typeof props.shadow === 'boolean') {
        return {
          x: props.shadow,
          y: props.shadow
        };
      }
      return props.shadow;
    });
    const style = computed(() => [props.containerStyle, {
      height: pxfy(props.height),
      maxHeight: pxfy(props.maxHeight)
    }]);
    const wrapperClassRef = computed(() => [prefixCls]);
    const containerClassRef = computed(() => [`${prefixCls}-container`, props.containerClass, !props.native && `${prefixCls}-hidden-native-bar`]);
    const handleScroll = event => {
      onScroll();
      const containerRefValue = containerRef.value;
      if (containerRefValue) {
        emit('scroll', event, containerRefValue);
      }
    };

    // contentRef 为 containerRef 的子元素，所以 containerRef 不需要再监听
    useResize(contentRef, () => {
      onUpdate();
      onScroll();
    }, computed(() => props.noresize), false);
    useResize(scrollbarRef, () => {
      onUpdate();
      onScroll();
    }, computed(() => props.noresize), false);
    onMounted(() => {
      // 等待content插槽内容渲染完毕用setTimeout
      if (!props.native) {
        setTimeout(onUpdate, 0);
      }
      setTimeout(onScroll, 0);
    });
    watch(() => props.minSize, () => {
      onUpdate();
      onScroll();
    }, {
      immediate: false
    });
    let rafId;
    const move = (type, to, duration) => {
      if (!duration || duration <= 0) {
        containerRef.value[type] = to;
        return;
      }
      const difference = to - containerRef.value[type];
      const perTick = difference / duration * 10;
      rafId = requestAnimationFrame(() => {
        containerRef.value[type] += perTick;
        if (containerRef.value[type] === to) {
          return;
        }
        move(type, to, duration - 10);
      });
    };
    const setScrollTop = (val, duration) => {
      move('scrollTop', val, duration);
    };
    const setScrollLeft = (val, duration) => {
      move('scrollLeft', val, duration);
    };
    const scrollToEnd = (direction, duration) => {
      if (direction === 'bottom') {
        move('scrollTop', contentRef.value.offsetHeight, duration);
      } else if (direction === 'right') {
        move('scrollLeft', contentRef.value.offsetWidth, duration);
      } else {
        move('scrollTop', contentRef.value.offsetHeight, duration);
        move('scrollLeft', contentRef.value.offsetWidth, duration);
      }
    };
    onBeforeUnmount(() => {
      if (rafId) {
        cancelAnimationFrame(rafId);
      }
    });
    return {
      scrollbarRef,
      containerRef,
      contentRef,
      style,
      prefixCls,
      setScrollTop,
      setScrollLeft,
      scrollToEnd,
      update: onUpdate,
      handleScroll,
      thumbMoveX,
      thumbMoveY,
      ratioX,
      ratioY,
      sizeHeight,
      sizeWidth,
      wrapperClassRef,
      containerClassRef,
      scrollX,
      scrollXRatio,
      scrollY,
      scrollYRatio,
      shadowRef
    };
  }
});

function render(_ctx, _cache, $props, $setup, $data, $options) {
  const _component_FBar = resolveComponent("FBar");
  return openBlock(), createElementBlock("div", {
    ref: "scrollbarRef",
    class: normalizeClass(_ctx.wrapperClassRef)
  }, [createElementVNode("div", {
    ref: "containerRef",
    class: normalizeClass(_ctx.containerClassRef),
    style: normalizeStyle(_ctx.style),
    onScroll: _cache[0] || (_cache[0] = function () {
      return _ctx.handleScroll && _ctx.handleScroll(...arguments);
    })
  }, [createElementVNode("div", {
    ref: "contentRef",
    class: normalizeClass(`${_ctx.prefixCls}-content`),
    style: normalizeStyle([_ctx.scrollX && {
      width: 'fit-content'
    }, _ctx.contentStyle])
  }, [renderSlot(_ctx.$slots, "default")], 6 /* CLASS, STYLE */)], 38 /* CLASS, STYLE, NEED_HYDRATION */), !_ctx.native ? (openBlock(), createElementBlock(Fragment, {
    key: 0
  }, [createVNode(_component_FBar, {
    thumbStyle: _ctx.thumbStyle,
    scrollbarRef: [_ctx.scrollbarRef],
    containerRef: _ctx.containerRef,
    move: _ctx.thumbMoveX,
    ratio: _ctx.ratioX,
    size: _ctx.sizeWidth,
    always: _ctx.always,
    style: normalizeStyle(_ctx.horizontalRatioStyle)
  }, null, 8 /* PROPS */, ["thumbStyle", "scrollbarRef", "containerRef", "move", "ratio", "size", "always", "style"]), createVNode(_component_FBar, {
    thumbStyle: _ctx.thumbStyle,
    scrollbarRef: [_ctx.scrollbarRef],
    containerRef: _ctx.containerRef,
    move: _ctx.thumbMoveY,
    ratio: _ctx.ratioY,
    size: _ctx.sizeHeight,
    vertical: "",
    always: _ctx.always,
    style: normalizeStyle(_ctx.verticalRatioStyle)
  }, null, 8 /* PROPS */, ["thumbStyle", "scrollbarRef", "containerRef", "move", "ratio", "size", "always", "style"])], 64 /* STABLE_FRAGMENT */)) : createCommentVNode("v-if", true), _ctx.shadowRef.x && _ctx.scrollX && _ctx.scrollXRatio < 1 ? (openBlock(), createElementBlock("div", {
    key: 1,
    class: normalizeClass(`${_ctx.prefixCls}-shadow-right`),
    style: normalizeStyle(_ctx.shadowStyle)
  }, null, 6 /* CLASS, STYLE */)) : createCommentVNode("v-if", true), _ctx.shadowRef.x && _ctx.scrollX && _ctx.scrollXRatio > 0 ? (openBlock(), createElementBlock("div", {
    key: 2,
    class: normalizeClass(`${_ctx.prefixCls}-shadow-left`),
    style: normalizeStyle(_ctx.shadowStyle)
  }, null, 6 /* CLASS, STYLE */)) : createCommentVNode("v-if", true), _ctx.shadowRef.y && _ctx.scrollY && _ctx.scrollYRatio < 1 ? (openBlock(), createElementBlock("div", {
    key: 3,
    class: normalizeClass(`${_ctx.prefixCls}-shadow-bottom`),
    style: normalizeStyle(_ctx.shadowStyle)
  }, null, 6 /* CLASS, STYLE */)) : createCommentVNode("v-if", true), _ctx.shadowRef.y && _ctx.scrollY && _ctx.scrollYRatio > 0 ? (openBlock(), createElementBlock("div", {
    key: 4,
    class: normalizeClass(`${_ctx.prefixCls}-shadow-top`),
    style: normalizeStyle(_ctx.shadowStyle)
  }, null, 6 /* CLASS, STYLE */)) : createCommentVNode("v-if", true)], 2 /* CLASS */);
}

script.render = render;
script.__file = "components/scrollbar/scrollbar.vue";

export { script as default };
