<template>
  <view :class="rateClass" :style="rateStyle">
    <view
      :class="bem.e('content')"
      :style="contentStyle"
      :id="rateId"
      @touchstart="onTouchStart"
      @touchmove.stop.prevent="onTouchMove"
      @mousedown="onMouseDown"
    >
      <view
        v-for="(item, i) in starList"
        :key="i"
        :class="bem.e('item')"
        :id="i === 0 ? firstStarId : undefined"
        :style="
          stringifyStyle({
            fontSize: size,
          })
        "
        @click="onClick($event, i)"
      >
        <view
          :class="bem.e('star-void')"
          :style="
            stringifyStyle({
              color: voidColor,
            })
          "
        >
          <template v-if="voidText">
            {{ voidText }}
          </template>
          <sar-icon v-else :name="voidIcon" :family="iconFamily" />
        </view>
        <view
          :class="bem.e('star')"
          :style="
            stringifyStyle({
              color,
              width: item.width,
            })
          "
        >
          <template v-if="text">
            {{ text }}
          </template>
          <sar-icon v-else :name="icon" :family="iconFamily" />
        </view>
      </view>
    </view>
  </view>
</template>

<script lang="ts">
import { defineComponent as _defineComponent } from "vue";
import { computed, getCurrentInstance, ref, watch } from "vue";
import {
  classNames,
  stringifyStyle,
  createBem,
  uniqid,
  getBoundingClientRect
} from "../utils";
import SarIcon from "../icon/icon.vue";
import { useFormContext, useFormItemContext } from "../form/common";
import { rateProps } from "./common";
const __default__ = {
  options: {
    virtualHost: true,
    styleIsolation: "shared"
  }
};
export default /* @__PURE__ */ _defineComponent({
  ...__default__,
  __name: "rate",
  props: rateProps,
  emits: ["update:model-value"],
  setup(__props, { expose: __expose, emit: __emit }) {
    __expose();
    const props = __props;
    const emit = __emit;
    const bem = createBem("rate");
    const formContext = useFormContext();
    const formItemContext = useFormItemContext();
    const isDisabled = computed(() => {
      return formContext?.disabled ?? props.disabled;
    });
    const isReadonly = computed(() => {
      return formContext?.readonly ?? props.readonly;
    });
    const innerValue = ref(props.modelValue ?? 0);
    watch(
      () => props.modelValue,
      () => {
        innerValue.value = props.modelValue ?? 0;
        if (props.validateEvent) {
          formItemContext?.onChange();
        }
      }
    );
    const rateId = uniqid();
    const firstStarId = uniqid();
    const instance = getCurrentInstance();
    const rateRect = ref();
    const firstStarRect = ref();
    const starList = computed(() => {
      return Array(props.count).fill(0).map((_, index) => {
        const diff = index + 1 - innerValue.value;
        const width = (diff <= 0 ? 1 : diff > 1 ? 0 : innerValue.value % 1) * 100 + "%";
        return {
          width
        };
      });
    });
    const onClick = async (event, index) => {
      if (isReadonly.value || isDisabled.value) {
        return;
      }
      let nextValue;
      if (props.allowHalf) {
        const { left: rateLeft, width: rateWidth } = await getBoundingClientRect(
          `#${rateId}`,
          instance
        );
        const { width: starWidth } = await getBoundingClientRect(
          `#${firstStarId}`,
          instance
        );
        const { clientX } = "touches" in event ? event.touches[0] : event;
        const offsetX = clientX - rateLeft;
        const gap = (rateWidth - props.count * starWidth) / (props.count - 1);
        const itemOffsetLeft = index * (starWidth + gap);
        const isHalf = offsetX - itemOffsetLeft <= starWidth / 2;
        nextValue = index + (isHalf ? 0.5 : 1);
      } else {
        nextValue = index + 1;
      }
      if (props.clearable && nextValue === innerValue.value) {
        nextValue = 0;
      }
      if (nextValue !== void 0 && nextValue !== innerValue.value) {
        innerValue.value = nextValue;
        emit("update:model-value", nextValue);
      }
    };
    const onTouchStart = () => {
      if (isReadonly.value || isDisabled.value) {
        return;
      }
      getBoundingClientRect(`#${rateId}`, instance).then((rect) => {
        rateRect.value = rect;
      });
      getBoundingClientRect(`#${firstStarId}`, instance).then((rect) => {
        firstStarRect.value = rect;
      });
    };
    const onTouchMove = (event) => {
      if (isReadonly.value || isDisabled.value) {
        return;
      }
      event.preventDefault();
      if (!rateRect.value || !firstStarRect.value) {
        return;
      }
      const { left: rateLeft, width: rateWidth } = rateRect.value;
      const { clientX } = event.touches[0];
      const offsetX = clientX - rateLeft;
      let nextValue;
      if (offsetX < 0) {
        nextValue = 0;
      } else {
        const { width: starWidth } = firstStarRect.value;
        const gap = (rateWidth - props.count * starWidth) / (props.count - 1);
        for (let i = props.count - 1; i >= 0; i--) {
          const left = i * (gap + starWidth);
          if (offsetX >= left) {
            const index = i + (props.allowHalf && offsetX <= left + starWidth / 2 ? 0.5 : 1);
            nextValue = index;
            break;
          }
        }
      }
      if (nextValue !== void 0 && nextValue !== innerValue.value) {
        innerValue.value = nextValue;
        emit("update:model-value", nextValue);
      }
    };
    const onMouseDown = () => {
      onTouchStart();
      const moveHandler = (event) => {
        event.preventDefault();
        onTouchMove({
          touches: [event],
          preventDefault: () => {
            event.preventDefault();
          }
        });
      };
      const upHandler = () => {
        document.removeEventListener("mouseup", upHandler);
        document.removeEventListener("mousemove", moveHandler);
      };
      document.addEventListener("mousemove", moveHandler);
      document.addEventListener("mouseup", upHandler);
    };
    const rateClass = computed(() => {
      return classNames(
        bem.b(),
        bem.m("disabled", isDisabled.value),
        bem.m("readonly", isReadonly.value),
        props.rootClass
      );
    });
    const rateStyle = computed(() => {
      return stringifyStyle(props.rootStyle);
    });
    const contentStyle = computed(() => {
      return stringifyStyle({
        gap: props.gap
      });
    });
    const __returned__ = { props, emit, bem, formContext, formItemContext, isDisabled, isReadonly, innerValue, rateId, firstStarId, instance, rateRect, firstStarRect, starList, onClick, onTouchStart, onTouchMove, onMouseDown, rateClass, rateStyle, contentStyle, get stringifyStyle() {
      return stringifyStyle;
    }, SarIcon };
    return __returned__;
  }
});
</script>

<style lang="scss">
@use './index.scss';
</style>