<script setup>
import { ref, computed, onMounted, watch } from "vue";
import { useNamespace } from "@yh-ui/hooks";
import { priceProps } from "./price";
defineOptions({ name: "YhPrice" });
const props = defineProps(priceProps);
const ns = useNamespace("price");
const displayValue = ref(props.animated ? 0 : Number(props.value));
const displayMax = ref(props.animated ? 0 : Number(props.maxValue));
let rafId = null;
const startAnimation = (fromValue, toValue, setter) => {
  const duration = 1e3;
  const startTime = performance.now();
  const from = fromValue;
  const animate = (currentTime) => {
    const elapsed = currentTime - startTime;
    const progress = Math.min(elapsed / duration, 1);
    const easeProgress = progress === 1 ? 1 : 1 - Math.pow(2, -10 * progress);
    setter(from + (toValue - from) * easeProgress);
    if (progress < 1) {
      rafId = requestAnimationFrame(animate);
    } else {
      setter(toValue);
    }
  };
  rafId = requestAnimationFrame(animate);
};
const triggerAllAnimations = () => {
  if (rafId) cancelAnimationFrame(rafId);
  startAnimation(displayValue.value, Number(props.value), (v) => displayValue.value = v);
  if (props.maxValue !== void 0) {
    startAnimation(displayMax.value, Number(props.maxValue), (v) => displayMax.value = v);
  }
};
onMounted(() => {
  if (props.animated) {
    triggerAllAnimations();
  }
});
watch(
  () => [props.value, props.maxValue],
  () => {
    if (props.animated) {
      triggerAllAnimations();
    } else {
      displayValue.value = Number(props.value);
      displayMax.value = Number(props.maxValue);
    }
  },
  { deep: true }
);
const format = (val) => {
  const num = isNaN(val) ? 0 : val;
  const fixed = num.toFixed(props.precision);
  if (props.thousandth) {
    const parts = fixed.split(".");
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    return parts.join(".");
  }
  return fixed;
};
const getParts = (formatted) => {
  const parts = formatted.split(".");
  return {
    integer: parts[0],
    decimal: parts[1] ? `.${parts[1]}` : ""
  };
};
const mainParts = computed(() => getParts(format(displayValue.value)));
const maxParts = computed(
  () => props.maxValue !== void 0 ? getParts(format(displayMax.value)) : null
);
const deleteParts = computed(
  () => props.deleteValue !== void 0 ? getParts(format(Number(props.deleteValue))) : null
);
const containerStyle = computed(() => {
  const styles = {
    "--yh-price-integer-size": typeof props.size === "number" ? `${props.size}px` : void 0,
    "--yh-price-decimal-scale": props.decimalScale.toString()
  };
  if (props.gradient) {
    const colors = Array.isArray(props.gradient) ? props.gradient : ["#ff4d4f", "#ff7875"];
    styles["background-image"] = `linear-gradient(to right, ${colors.join(", ")})`;
    styles["-webkit-background-clip"] = "text";
    styles["background-clip"] = "text";
    styles["color"] = "transparent";
  }
  return { ...styles, ...props.themeOverrides };
});
</script>

<template>
  <div
    :class="[ns.b(), ns.m(props.size), ns.is('line-through', props.lineThrough), ns.is('bold', props.bold), ns.is('split', props.split), ns.is('gradient', !!props.gradient)]"
    :style="containerStyle"
  >
    <!-- 标签区域 -->
    <div v-if="props.tag || $slots.tag" :class="[ns.e('tag'), ns.em('tag', props.tagType)]">
      <slot name="tag">{{ props.tag }}</slot>
    </div>

    <!-- 前缀/约等于 -->
    <div v-if="props.approx" :class="ns.e('approx')">~</div>
    <div v-if="props.prefix" :class="ns.e('prefix')">
      <slot name="prefix">{{ props.prefix }}</slot>
    </div>

    <!-- 符号容器 -->
    <div v-if="props.symbolPosition === 'before'" :class="ns.e('symbol')">
      <slot name="symbol">{{ props.symbol }}</slot>
    </div>

    <!-- 价格数值主体 -->
    <div :class="ns.e('main')">
      <div :class="ns.e('integer')">{{ mainParts.integer }}</div>
      <div :class="ns.e('decimal')">{{ mainParts.decimal }}</div>

      <!-- 区间模式 -->
      <template v-if="maxParts">
        <div :class="ns.e('separator')">-</div>
        <div :class="ns.e('integer')">{{ maxParts.integer }}</div>
        <div :class="ns.e('decimal')">{{ maxParts.decimal }}</div>
      </template>
    </div>

    <div v-if="props.symbolPosition === 'after'" :class="ns.e('symbol')">
      <slot name="symbol">{{ props.symbol }}</slot>
    </div>

    <!-- 单位/后缀 -->
    <div v-if="props.unit || $slots.unit" :class="ns.e('unit')">
      <slot name="unit">{{ props.unit }}</slot>
    </div>
    <div v-if="props.suffix" :class="ns.e('suffix')">
      <slot name="suffix">{{ props.suffix }}</slot>
    </div>

    <!-- 原价/划线价对比 -->
    <div v-if="deleteValue !== void 0 && deleteParts" :class="ns.e('delete')">
      <span v-if="deleteLabel" :class="ns.e('delete-label')">{{ deleteLabel }}</span>
      <span :class="ns.e('delete-symbol')">{{ symbol }}</span>
      <span>{{ deleteParts.integer }}{{ deleteParts.decimal }}</span>
    </div>
  </div>
</template>

<style>
@charset "UTF-8";
/**
 * YH-UI Sass Variables
 * 原具体的 CSS 变量输出规则 (:root, html.dark 等) 已移至 root.scss，以防止各组件样式编译时产生重复的全局变量 CSS 冗余。
 */
.yh-price {
  --yh-price-color: var(--yh-color-danger);
  --yh-price-font-family: var(--yh-font-family);
  --yh-price-integer-size: 1.25em;
  --yh-price-symbol-size: 0.75em;
  --yh-price-decimal-scale: 0.8;
  --yh-price-tag-bg: var(--yh-color-danger);
  display: inline-flex;
  align-items: baseline;
  vertical-align: middle;
  color: var(--yh-price-color);
  font-family: var(--yh-price-font-family);
  line-height: 1;
  white-space: nowrap;
  flex-wrap: wrap;
}
.yh-price.is-bold {
  font-weight: var(--yh-font-weight-bold);
}

.yh-price.is-gradient {
  display: inline-flex;
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  transition: all 0.3s ease;
}

.yh-price.is-line-through {
  color: var(--yh-text-color-placeholder);
  text-decoration: line-through;
  font-weight: var(--yh-font-weight-normal);
  --yh-price-color: var(--yh-text-color-placeholder);
}

.yh-price__main {
  display: inline-flex;
  align-items: baseline;
}

.yh-price__separator {
  margin: 0 2px;
  font-size: 0.8em;
}

.yh-price__approx {
  font-size: 0.8em;
  margin-right: 2px;
}

.yh-price__prefix {
  font-size: 0.7em;
  margin-right: 2px;
  font-weight: var(--yh-font-weight-normal);
}

.yh-price__symbol {
  font-size: var(--yh-price-symbol-size);
  margin-right: 1px;
  font-family: sans-serif;
}

.yh-price__integer {
  font-size: var(--yh-price-integer-size);
  font-variant-numeric: tabular-nums;
}

.yh-price__decimal {
  font-size: calc(100% * var(--yh-price-decimal-scale));
  font-variant-numeric: tabular-nums;
}

.yh-price__unit {
  font-size: 0.75em;
  margin-left: 2px;
  font-weight: var(--yh-font-weight-normal);
  color: var(--yh-text-color-secondary);
}

.yh-price__suffix {
  font-size: 0.75em;
  margin-left: 2px;
  font-weight: var(--yh-font-weight-normal);
}

.yh-price__tag {
  display: inline-flex;
  align-items: center;
  padding: 2px 4px;
  font-size: 10px;
  line-height: 1;
  border-radius: var(--yh-radius-sm);
  background-color: var(--yh-price-tag-bg);
  color: var(--yh-color-white);
  margin-right: 6px;
  font-weight: normal;
  font-style: normal;
  transform: translateY(-1px);
}
.yh-price__tag--primary {
  background-color: var(--yh-color-primary);
}

.yh-price__tag--success {
  background-color: var(--yh-color-success);
}

.yh-price__tag--warning {
  background-color: var(--yh-color-warning);
}

.yh-price__tag--danger {
  background-color: var(--yh-color-danger);
}

.yh-price__tag--info {
  background-color: var(--yh-color-info);
}

.yh-price__delete {
  display: inline-flex;
  align-items: baseline;
  font-size: 0.7em;
  color: var(--yh-text-color-placeholder);
  text-decoration: line-through;
  margin-left: 8px;
  font-weight: normal;
}
.yh-price__delete-label {
  margin-right: 2px;
  text-decoration: none;
  display: inline-block;
}

.yh-price {
  /* Standard sizes */
}
.yh-price--large {
  font-size: 24px;
  --yh-price-integer-size: 1.4em;
}

.yh-price--default {
  font-size: 16px;
}

.yh-price--small {
  font-size: 13px;
  --yh-price-integer-size: 1.1em;
}
</style>
