<template>
  <view
    class="nana-slider"
    :id="id"
    :style="{
      opacity: disabled ? 0.6 : 1,
      width: direction == 'horizontal' ? undefined : themeContext.resolveSize(dotSize),
      height: direction == 'vertical' ? undefined : themeContext.resolveSize(dotSize),
      minWidth: themeContext.resolveSize(dotSize),
      minHeight: themeContext.resolveSize(dotSize),
      ...innerStyle,
    }"
    @touchstart="handleTouchStart"
    @touchmove="handleTouchMove"
    @touchend="handleTouchEnd"
    @touchcancel="handleTouchEnd"
    @mousedown="handleTouchStart"
    @mousemove="handleTouchMove"
    @mouseup="handleTouchEnd"
  >
    <view
      class="dot"
      :style="{
        ...themeStyles.toggleDot.value,
        width: themeContext.resolveSize(dotSize),
        height: themeContext.resolveSize(dotSize),
        borderRadius: themeContext.resolveSize(dotSize / 2),
        backgroundColor: themeContext.resolveThemeColor(dotColor),
        left: direction == 'horizontal' ? `calc(${valuePrecent}% - ${themeContext.resolveSize(dotSize / 2)})` : undefined ,
        top: direction == 'vertical' ? `calc(${valuePrecent}% - ${themeContext.resolveSize(dotSize / 2)})` : undefined,
        ...dotStyle,
      }"
    />
    <view class="bar" :style="{
      backgroundColor: themeContext.resolveThemeColor(inactiveColor),
      width: direction == 'horizontal' ? '100%' : themeContext.resolveThemeSize(size),
      height: direction == 'vertical' ? '100%' : themeContext.resolveThemeSize(size),
    }">
      <view 
        class="active" 
        :style="{
          backgroundColor: themeContext.resolveThemeColor(activeColor),
          width: direction == 'horizontal' ? `${valuePrecent}%` : themeContext.resolveThemeSize(size),
          height: direction == 'vertical' ? `${valuePrecent}%` : themeContext.resolveThemeSize(size),
        }"
      />
    </view>
  </view>
</template>

<script setup lang="ts">
import { computed, getCurrentInstance, onMounted, toRef } from 'vue';
import { propGetThemeVar, useTheme, type ViewStyle } from '../theme/ThemeDefine';
import { DynamicVar } from '../theme/ThemeTools';
import { useFieldChildValueInjector } from './FormContext';
import { RandomUtils } from '@imengyu/imengyu-utils';

export interface SliderProps {
  /**
   * 数值
   * @default 50
   */
  modelValue?: number;
  /**
   * 滑动方向
   * @default horizontal
   */
  direction?: 'horizontal' | 'vertical';
  /**
   * 主颜色
   * @default primary
   */
  activeColor?: string;
  /**
   * 反色
   * @default grey
   */
  inactiveColor?: string;
  /**
   * 条的大小
   * @default 6
   */
  size?: string|number;
  /**
   * 开关点的颜色
   * @default lightButton
   */
  dotColor?: string;
  /**
   * 开关大小
   * @default 40
   */
  dotSize?: number;
  /**
   * 点的自定义样式
   */
  dotStyle?: ViewStyle;
  /**
   * 是否禁用
   * @default false
   */
  disabled?: boolean;
  /**
   * 最小值
   * @default 0
   */
  min?: number;
  /**
   * 最大值
   * @default 100
   */
  max?: number;
  /**
   * 步长
   */
  step?: number;
  /**
   * 内部样式
   */
  innerStyle?: ViewStyle,
}


const emit = defineEmits([ 'update:modelValue' ])

const props = withDefaults(defineProps<SliderProps>(), {
  modelValue: 50,
  activeColor: () => propGetThemeVar('SliderActiveColor', 'primary'),
  inactiveColor: () => propGetThemeVar('SliderInactiveColor', 'background.switch'),
  dotColor: () => propGetThemeVar('SliderDotColor', 'lightButton'),
  dotSize: () => propGetThemeVar('SliderDotSize', 40),
  disabled: false,
  direction: 'horizontal',
  min: 0,
  max: 100,
  size: () => propGetThemeVar('SliderSize', 6),
});

const themeContext = useTheme();
const themeStyles = themeContext.useThemeStyles({
  toggleDot: {
    boxShadow: DynamicVar('SliderDotShadow', 'rgba(0, 0, 0, 0.1) 2px 2px 8px 2px'),
  },
});

const valuePrecent = computed(() => {
  return (value.value - props.min) / (props.max - props.min) * 100
});

const {
  value,
  updateValue,
  context,
} = useFieldChildValueInjector(
  toRef(props, 'modelValue'), 
  (v) => emit('update:modelValue', v)
);

const instance = getCurrentInstance();
const id = RandomUtils.genNonDuplicateID(12);
let absLeft = 0;
let absWidth = 0;
let pressed = false;

function doUpdateValue(v: number) {
  v = Math.max(props.min, Math.min(props.max, v));
  if (props.step)
    v = Math.round(v / props.step) * props.step;
  updateValue(v);
}
function handleDrag(x: number) {
  let v = (x - absLeft) / absWidth;
  v = v * (props.max - props.min) + props.min;
  if (v !== value.value)
    doUpdateValue(v);
}

function handleTouchStart(e: any) {
  if (props.disabled)
    return;
  e.stopPropagation();
  const query = uni.createSelectorQuery();
  query
    // #ifdef MP
    .in(instance)
    // #endif
    .select('#' + id)
    .boundingClientRect((res) => {
    if (res) {
      absLeft = (res as any).left;
      absWidth = (res as any).width;
      pressed = true;
    }
    handleDrag(e.touches[0]?.clientX);
  }).exec();
}
function handleTouchMove(e: any) {
  if (props.disabled)
    return;
  if (!pressed)
    return;
  e.stopPropagation();
  handleDrag(e.touches[0]?.clientX);
}
function handleTouchEnd() {
  pressed = false;
}

defineOptions({
  options: {
    styleIsolation: "shared",
    virtualHost: true,
  }
})
</script>

<style lang="scss">
.nana-slider {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  position: relative;
  overflow: visible;
  flex: 1;

  .bar {
    display: flex;
    position: relative;
    overflow: hidden;

    .active {
      position: absolute;
    }
  }
  .dot {
    display: flex;
    position: absolute;
    z-index: 10,
  }
}


</style>