<template>
  <Popup
    v-bind="props"
    position="bottom"
    round
    :size="`${currentHeight}px`"
    :show="show"
    :noTransition="touching"
    @close="onCancelClick"
  >
    <FlexCol 
      position="relative"
      backgroundColor="white" 
      :innerStyle="{
        ...themeStyles.bottomSheet.value,
        height: `100%`,
        width: `100%`,
        ...innerStyle,
      }"
    >
      <view 
        v-if="enableDrag"
        :style="themeStyles.dragHandleContainer.value"
        @touchstart="onDragStart"
        @touchmove="onDragMove"
        @touchend="onDragEnd"
      >
        <view 
          :style="{
            ...themeStyles.dragHandle.value,
            width: themeContext.resolveSize(dragHandleSize),
            backgroundColor: themeContext.resolveThemeColor(dragHandleColor),
          }" 
        />
      </view>
      <scroll-view 
        :scroll-y="true"
        :style="{
          height: `100%`,
        }"
      >
        <slot name="content" :close="onCancelClick" />
      </scroll-view>
    </FlexCol>
  </Popup>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { propGetThemeVar, useTheme, type ViewStyle } from '../theme/ThemeDefine';
import { DynamicColor, DynamicSize } from '../theme/ThemeTools';
import Popup from './Popup.vue';
import FlexCol from '../layout/FlexCol.vue';
import type { PopupProps } from './Popup.vue';

export interface BottomSheetProps extends Omit<PopupProps, 'onClose'|'position'|'position'|'size'> {
  /**
   * 是否显示
   * @default true
   */
  show: boolean;
  /**
   * 拖动把手颜色
   * @default 'grey'
   */
  dragHandleColor?: string;
  /**
   * 拖动把手大小
   * @default 100
   */
  dragHandleSize?: number;
  /**
   * 拖动时使高度吸附到指定高度
   * @default undefined
   */
  dragSnapHeights?: number[]|undefined;
  /**
   * 是否启用拖动
   * @default true
   */
  enableDrag?: boolean;
  /**
   * 底部弹窗大小(px)
   * @default '300
   */
  height?: number;
  /**
   * 拖动最大高度(px)
   * @default 1000
   */
  dragMaxHeight?: number;
  /**
   * 拖动最小高度(px)
   * @default 100
   */
  dragMinHeight?: number;

  innerStyle?: ViewStyle;
}

export interface BottomSheetExpose {
  setDragHeight: (height: number) => void;
  getDragHeight: () => number;
  setDragHeightToMax: () => void;
  setDragHeightToMin: () => void;
}

const emit = defineEmits([ 'close', 'select' ]);
const props = withDefaults(defineProps<BottomSheetProps>(), {
  enableDrag: true,
  dragHandleColor: () => propGetThemeVar('BottomSheetDragHandleColor', 'grey'),
  dragHandleSize: () => propGetThemeVar('BottomSheetDragHandleSize', 200),
  centerWidth: () => propGetThemeVar('BottomSheetCenterWidth', '600rpx'),
  height: () => propGetThemeVar('BottomSheetHeight', 300),
  dragMaxHeight: () => propGetThemeVar('BottomSheetDragMaxHeight', 1000),
  dragMinHeight: () => propGetThemeVar('BottomSheetDragMinHeight', 100),
});
const themeContext = useTheme();
const themeStyles = themeContext.useThemeStyles({
  bottomSheet: {
    borderTopLeftRadius: DynamicSize('BottomSheetBorderRadius', 10),
    borderTopRightRadius: DynamicSize('BottomSheetBorderRadius', 10),
    backgroundColor: DynamicColor('BottomSheetBackgroundColor', 'white'),
  },
  dragHandleContainer: {
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
  },
  dragHandle: {
    height: DynamicSize('BottomSheetDragHandleSize', 10),
    borderRadius: DynamicSize('BottomSheetDragHandleBorderRadius', 10),
    marginTop: DynamicSize('BottomSheetDragHandleMarginVertical', 25),
    marginBottom: DynamicSize('BottomSheetDragHandleMarginVertical', 25),
  },
});

const currentHeight = ref(props.height);
const touching = ref(false);
let touchStartY = 0;
let touchStartHeight = 0;

function onDragStart(e: TouchEvent) {
  if (!props.enableDrag) return;
  e.preventDefault();
  e.stopPropagation();
  touchStartY = e.touches[0].clientY;
  touchStartHeight = currentHeight.value;
  touching.value = true;
}
function onDragMove(e: TouchEvent) {
  if (!props.enableDrag || !touching.value) return;
  e.preventDefault();
  e.stopPropagation();
  const deltaY = e.touches[0].clientY - touchStartY;
  currentHeight.value = Math.max(props.dragMinHeight, 
    Math.min(props.dragMaxHeight, touchStartHeight - deltaY)
  );
}
function onDragEnd(e: TouchEvent) {
  if (!props.enableDrag) return;
  e.preventDefault();
  e.stopPropagation();
  touching.value = false;

  //吸附到指定高度
  if (props.dragSnapHeights) {
    // 使当前高度吸附到最近的指定高度
    const snapHeights = props.dragSnapHeights.slice().sort((a, b) => a - b);
    let nearest = snapHeights[0];
    let minDist = Math.abs(currentHeight.value - snapHeights[0]);
    for (let i = 1; i < snapHeights.length; i++) {
      const dist = Math.abs(currentHeight.value - snapHeights[i]);
      if (dist < minDist) {
        minDist = dist;
        nearest = snapHeights[i];
      }
    }
    currentHeight.value = nearest;
  }
}

function onCancelClick() {
  emit('close');
}

defineExpose<BottomSheetExpose>({
  setDragHeight: (height: number) => {
    currentHeight.value = height;
  },
  setDragHeightToMax: () => {
    currentHeight.value = props.dragMaxHeight;
  },
  setDragHeightToMin: () => {
    currentHeight.value = props.dragMinHeight;
  },
  getDragHeight: () => {
    return currentHeight.value;
  },
});

</script>