<template>
  <view 
    :class="['nana-badge', standalone ? 'standalone' : '']"
    :style="containerStyle"
  >
    <slot />
    <SimpleTransition name="badge" :show="showBadge" :duration="3000">
      <template #show="{ classNames }">
        <view :class="['nana-badge-inner',...classNames]" :style="currentStyle">
          <VerticalScrollText v-if="anim" center :innerStyle="textStyle" :numberString="content2" />
          <Text v-else :innerStyle="textStyle" :text="content2" />
        </view>
      </template>
    </SimpleTransition>
  </view>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import { propGetThemeVar, useTheme, type TextStyle, type ViewStyle } from '../theme/ThemeDefine';
import { selectStyleType } from '../theme/ThemeTools';
import VerticalScrollText from '../typography/VerticalScrollText.vue';
import Text from '../basic/Text.vue';
import SimpleTransition from '../anim/SimpleTransition.vue';

type BadgePositionTypes = 'topRight'|'topLeft'|'bottomRight'|'bottomLeft';

export interface BadgeProps {
  /**
   * 控制是否显示
   * @default true
   */
  show?: boolean,
  /**
   * 独立显示
   */
  standalone?: boolean;
  /**
   * 徽标内容
   */
  content?: string|number,
  /**
   * 徽标数字最大值，如果徽标内容是数字，并且超过最大值，则显示 xx+。
   */
  maxCount?: number,
  /**
   * 徽标颜色
   * @default danger
   */
  color?: string,
  /**
   * 是否增加描边
   * @default false
   */
  border?: boolean;
  /**
   * 描边宽度
   * @default 2
   */
  borderWidth?: number;
  /**
   * 描边颜色
   * @default white
   */
  borderColor?: string;
  /**
   * 徽标在父级所处位置
   * @default 'top-right'
   */
  position?: BadgePositionTypes;
  /**
   * 是否在切换时有动画效果
   * @default false
   */
  anim?: boolean,
  /**
   * 徽标定位偏移
   */
  offset?: { x: number, y: number };
  /**
   * 徽标自定义样式
   */
  badgeStyle?: ViewStyle;
  /**
   * 徽标文字自定义样式
   */
  textStyle?: TextStyle;
  /**
   * 外层容器样式
   */
  containerStyle?: ViewStyle;
  /**
   * 徽标无文字情况下的徽标大小
   * @default 10
   */
  badgeSize?: number;
  /**
   * 字号
   * @default 12.5
   */
  fontSize?: number,
  /**
   * 圆角的大小
   * @default 20
   */
  radius?: number;
  /**
   * 徽标有文字情况下的垂直内边距
   * @default 2
   */
  paddingVertical?: number,
  /**
   * 徽标有文字情况下的水平内边距
   * @default 4
   */
  paddingHorizontal?: number,
  /**
   * 如果 content===0 是否隐藏红点
   * @default true
   */
  hiddenIfZero?: boolean;
}

const themeContext = useTheme();

const props = withDefaults(defineProps<BadgeProps>(), {
  color: 'danger',
  show: true,
  anim: () => propGetThemeVar('BadgeAnim', false),
  content: '',
  border: () => propGetThemeVar('BadgeBorder', false),
  borderWidth: () => propGetThemeVar('BadgeBorderWidth', 4),
  borderColor: () => propGetThemeVar('BadgeBorderColor', 'white'),
  position: () => propGetThemeVar('BadgePosition', 'topRight'),
  offset: () => propGetThemeVar('BadgeOffset', { x: 0, y: 0 }),
  badgeSize: () => propGetThemeVar('BadgeSize', 18),
  radius: () => propGetThemeVar('BadgeRadius', 20),
  fontSize: () => propGetThemeVar('BadgeFontSize', 24),
  paddingVertical: () => propGetThemeVar('BadgePaddingVertical', 4),
  paddingHorizontal: () => propGetThemeVar('BadgePaddingHorizontal', 8),
  hiddenIfZero: true,
});

//样式生成
const currentStyle = computed(() => {
  const size = themeContext.resolveThemeSize(props.badgeSize);
  return {
    backgroundColor: themeContext.resolveThemeColor(props.color),
    borderRadius: themeContext.resolveThemeSize(props.radius),
    border: props.border ? `${themeContext.resolveThemeSize(props.borderWidth)} solid ${themeContext.resolveThemeColor(props.borderColor)}` : undefined,
    minWidth: props.content ? themeContext.resolveThemeSize(props.fontSize) : undefined,
    padding: `${themeContext.resolveThemeSize(props.paddingVertical)} ${themeContext.resolveThemeSize(props.paddingHorizontal)}`,
    ...props.badgeStyle,
    ...(props.standalone ? {} : selectStyleType<TextStyle, BadgePositionTypes>(props.position, 'topRight', {
      topRight: {
        transform: `translate(50%, -50%)`,
        top: themeContext.resolveSize(props.offset.y),
        right: themeContext.resolveSize(props.offset.x),
      },
      topLeft: {
        transform: `translate(-50%, -50%)`,
        top: themeContext.resolveSize(props.offset.y),
        left: themeContext.resolveSize(props.offset.x),
      },
      bottomRight: {
        transform: `translate(50%, 50%)`,
        bottom: themeContext.resolveSize(props.offset.y),
        right: themeContext.resolveSize(props.offset.x),
      },
      bottomLeft: {
        transform: `translate(-50%, 50%)`,
        bottom: themeContext.resolveSize(props.offset.y),
        left: themeContext.resolveSize(props.offset.x),
      },
    })),
    ...(
      props.content ? {} : {
        width: size,
        height: size,
        borderRadius: '50%',
        padding: undefined,
      }
    ),
  }
});

const textStyle = computed(() => {
  const fontSize = themeContext.resolveThemeSize(props.fontSize, 24);
  return {
    fontSize: fontSize,
    color: themeContext.resolveThemeColor('BadgeTextColor', 'white'),
    textAlign: 'center',
    ...props.textStyle,
  }
})

const content2 = computed(() => {
  if (typeof props.content !== 'undefined') {
    if (typeof props.content === 'number') {
      return (props.maxCount && props.content > props.maxCount) ? `${props.maxCount}+` : props.content.toString();
    } else
      return props.content;
  }
  return '';
});

const showBadge = computed(() => 
  props.show && (!props.hiddenIfZero || 
  (props.hiddenIfZero && props.content !== 0 && props.content !== '0'))
);

</script>

<style lang="scss">
.nana-badge {
  position: relative;
  display: inline-flex;
  width: auto;
  height: auto;
  overflow: visible;

  .badge-enter-active,
  .badge-leave-active {
    opacity: 1;
    transform: scale(1);
    transition: all 0.3s ease-in-out;
  }

  .badge-enter-from,
  .badge-leave-to {
    transform: scale(0);
    opacity: 0;
  }

  &.standalone {
    position: relative;

    .nana-badge-inner {
      position: relative;
      z-index: 100;
    }
  }
}
.nana-badge-inner {
  position: absolute;
  z-index: 100;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
  align-self: flex-start;
  overflow: hidden;
  flex-shrink: 0;
}


</style>