<template>
  <view 
    :id="id"
    class="nana-rate"
    @touchstart="handleTouchStart"
    @touchmove="handleTouchMove"
    @touchend="handleTouchEnd"
    @mouseup="handleTouchEnd"
    @mousedown="handleTouchStart"
    @mousemove="handleTouchMove"
  >
    <template
      v-for="i of count"
      :key="i"
    >
      <view v-if="i - 1 === Math.floor(value) && i - 1 < Math.ceil(value)" class="active-half">
        <view :style="(starActiveHalfStyle as any)">
          <Icon 
            :icon="icon"
            v-bind="props.starActiveStyle"
            :color="disabled ? starDisableColor : starActiveColor"
            :size="size" 
            :style="starActiveStyle" 
          />
        </view>
        <Icon 
          :icon="voidIcon" 
          v-bind="props.starStyle"
          :color="disabled ? starDisableColor : starColor"
          :size="size"
          :style="starDeactiveStyle"
        />
      </view>
      <Icon 
        v-else-if="i <= value" 
        :icon="icon" 
        v-bind="props.starActiveStyle"
        :color="disabled ? starDisableColor : starActiveColor"
        :size="size" 
        :style="starActiveStyle"
      />
      <Icon
        v-else-if="i > value" 
        :icon="voidIcon" 
        v-bind="props.starStyle" 
        :color="disabled ? starDisableColor : starColor" 
        :size="size" 
        :style="starDeactiveStyle"
      />
    </template>
  </view>
</template>

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

export interface RateProps {
  /**
   * 评星组件参数值
   * @default 0
   */
  modelValue?: number;
  /**
   * 星星的数量
   * @default 5
   */
  count?: number;
  /**
   * 是否可以为0星
   * @default false
   */
  canbeZero?: boolean,
  /**
   * 星星未激活自定义样式
   */
  starStyle?: IconProps;
  /**
   * 星星激活自定义样式
   */
  starActiveStyle?: IconProps;
  /**
   * 星星激活的颜色
   * @default warning
   */
  starActiveColor?: string;
  /**
   * 星星未激活的颜色
   * @default grey
   */
  starColor?: string;
  /**
   * 星星禁用的颜色
   * @default grey
   */
  starDisableColor?: string;
  /**
   * 选中时的图标
   * @default 'favorite-filling'
   */
  icon?: string;
  /**
   * 未选中时的图标
   * @default 'favorite'
   */
  voidIcon?: string;
  /**
   * 星星之间的间距
   * @default 3
   */
  space?: number;
  /**
   * 用户是否可以选择出半星
   * @default false
   */
  half?: boolean;

  /**
   * 是否只读
   * @default false
   */
  readonly?: boolean;
  /**
   * 评星组件是否禁用
   * @default false
   */
  disabled?: boolean;
  /**
   * 评星组件大小
   * @default 48
   */
  size?: number;
}

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

const props = withDefaults(defineProps<RateProps>(), {
  modelValue: 0,
  count: 5,
  starActiveColor: () => propGetThemeVar('RateStarActiveColor', 'warning'),
  starColor: () => propGetThemeVar('RateStarColor', 'grey'),
  starDisableColor: () => propGetThemeVar('RateStarDisableColor', 'grey'),
  icon: () => propGetThemeVar('RateIcon', 'favorite-filling'),
  voidIcon: () => propGetThemeVar('RateVoidIcon', 'favorite'),
  space: () => propGetThemeVar('RateSpace', 3),
  size: () => propGetThemeVar('RateSize', 48),
});

const themeContext = useTheme();

const starActiveStyle = computed(() => ({
  marginRight: themeContext.resolveThemeSize(props.space),
  ...props.starActiveStyle,
}));
const starActiveHalfStyle = computed(() => ({
  ...props.starActiveStyle,
  position: 'absolute',
  left: 0,
  top: 0,
  width: '50%',
  overflow: 'hidden',
  zIndex: 1,
}));
const starDeactiveStyle = computed(() => ({
  marginRight: themeContext.resolveThemeSize(props.space),
  ...props.starStyle,
}));

const id = RandomUtils.genNonDuplicateID(12);
const instance = getCurrentInstance();
const width = computed(() => (props.size + props.space) * props.count);

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

let absLeft = 0;
let pressed = false;

function handleDrag(x: number) {
  let v = (x - absLeft) / rpx2px(width.value) * props.count;

  if (props.half) {
    let demcial = v - Math.floor(v);
    if (demcial < 0.2) demcial = 0;
    else if (demcial > 0.8) demcial = 1;
    else demcial = 0.5;
    v = Math.floor(v) + demcial;
  }
  else {
    v = Math.ceil(v);
  }
  if (v === 0 && !props.canbeZero)
    v = props.half ? 0.5 : 1;

  v = Math.max(0, Math.min(v, props.count));

  if (v !== value.value) {
    updateValue(v);
  }
}

function handleTouchStart(e: any) {
  if (props.readonly || props.disabled)
    return;
  e.stopPropagation();
  const query = uni.createSelectorQuery();
  query
    .in(instance)
    .select('#' + id)
    .boundingClientRect((res) => {
    if (res)
      absLeft = (res as any).left;
    handleDrag(e.touches[0]?.clientX);
    pressed = true;
  }).exec();
}
function handleTouchMove(e: any) {
  if (props.readonly || 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-rate {
  display: flex;
  flex-direction: row;
  position: relative;
  overflow: hidden;

  .active-half {
    position: relative;
  }
}
</style>