<template>
  <SimpleTransition name="back-to-top" :show="showState" :duration="2000">
    <template #show="{ classNames }">
      <view 
        :class="[ 'nana-back-to-top', ...classNames ]"
        :style="{
          right: themeContext.resolveThemeSize(props.right),
          bottom: themeContext.resolveThemeSize(props.bottom),
          zIndex: props.zIndex,
        }"
        @click="onClick"
      >
        <slot>
          <IconButton 
            :icon="props.icon"
            :size="40"
            :color="themeContext.resolveThemeColor(props.iconColor)"
            :buttonStyle="{
              ...buttonStyle,
              ...innerStyle,
            }"
            shape="round"
          />
        </slot>
      </view>
    </template>
  </SimpleTransition>
</template>

<script setup lang="ts">
import { onPageScroll } from '@dcloudio/uni-app';
import { useTheme, type ViewStyle } from '../theme/ThemeDefine';
import IconButton from '../basic/IconButton.vue';
import { ref, watch, type Ref } from 'vue';
import { DynamicColor, DynamicSize, DynamicVar } from '../theme/ThemeTools';
import SimpleTransition from '../anim/SimpleTransition.vue';

const themeContext = useTheme();

export interface BackToTopProps {
  /**
   * 组件距离右侧的距离
   * @default 40
   */
  right?: number|string;
  /**
   * 组件距离底部的距离
   * @default 40
   */
  bottom?: number|string;
  /**
   * 当容器滚动距离大于该值时显示组件(像素)
   * @default 200
   */
  showScrollValue?: number;
  /**
   * 组件的z-index
   * @default 100
   */
  zIndex?: number;
  /**
   * 是否自定义监听滚动容器，否则为监听页面滚动。
   * @default false
   */
  customScrollValue?: boolean;
  /**
   * 内部显示的图标。
   * @default 'arrow-up'
   */
  icon?: string;
  /**
   * 内部图标颜色
   * @default 'white'
   */
  iconColor?: string;
  /**
   * 内部图标样式
   */
  innerStyle?: ViewStyle;
}
export interface BackToTopInstance {
  /**
   * 滚动事件，用于自定义滚动容器，若要更换监听的滚动容器，将其绑定至scroll-view的滚动事件上即可：
   * ```
   * <scroll-view @scroll="onScroll"></scroll-view>
   * ```
   * @param e 
   */
  onScroll: (e: any) => void;

  /**
   * 自定义滚动容器的滚动距离
   */
  customScrollTop: Ref<number>;
}

const emit = defineEmits([ 
  'click',
  'show',
  'hide'
]);
const props = withDefaults(defineProps<BackToTopProps>(), {
  showScrollValue: 200,
  zIndex: 100,
  icon: 'arrow-up-bold',
  iconColor: 'white',
  customScrollValue: false,
  right: 40,
  bottom: 40,
});

const buttonStyle = themeContext.useThemeStyle({
  width: DynamicSize('BackToTopButtonWidth', 80),
  height: DynamicSize('BackToTopButtonHeight', 80),
  borderRadius: '50%',
  boxShadow: DynamicVar('BackToTopButtonBoxShadow', '0 0 8px 0 rgba(0,0,0,0.2)'),
  backgroundColor: DynamicColor('BackToTopButtonBackgroundColor', 'primary'),
});

const customScrollTop = ref(0);
const showState = ref(false);

watch(showState, (v) => {
  if (v)
    emit('show');
  else
    emit('hide');
});

function onScroll(value: number) {
  customScrollTop.value = value;
  showState.value = value > props.showScrollValue;
}
function onClick() {
  if (props.customScrollValue) {
    customScrollTop.value = 0;
  } else {
    uni.pageScrollTo({
      scrollTop: 0,
    });
  }
  emit('click');
}

onPageScroll((e) => {
  if (props.customScrollValue)
    return;
  onScroll(e.scrollTop);
});

defineExpose<BackToTopInstance>({
  customScrollTop,
  onScroll(e) {
    console.log('onScroll', e);
    if (props.customScrollValue)
      onScroll(e.detail.scrollTop);
  },
})
defineOptions({
  options: {
    virtualHost: true,
    styleIsolation: "shared",
  },
});
</script>

<style lang="scss">
.nana-back-to-top {
  position: fixed;
  transition: all 0.3s ease-in-out;

  &.back-to-top-enter-active,
  &.back-to-top-leave-active {
    transform: scale(1);
    opacity: 1;
  }

  &.back-to-top-enter-from,
  &.back-to-top-leave-to {
    transform: scale(0);
    opacity: 0;
  }
}
</style>