<template>
  <view 
    :id="id"
    class="nana-image-wrapper"
    :style="style"
    :class="innerClass"
    @click="handleClick"
  >
    <template v-if="mode !== 'borderImage'">
      <view v-if="showBackgroundEffect" :style="(backgroundEffectStyle as any)">
      </view>
      <view v-if="showBackgroundEffect" :style="(backgroundEffectStyle2 as any)">
      </view>
      <image 
        :style="{
          width: precentOrFull(style.width),
          height: precentOrFull(style.height),
          borderRadius: themeContext.resolveThemeSize(props.radius),
        }"
        :mode="(mode as any)"
        :lazyLoad="$attrs.lazyLoad"
        :fadeShow="$attrs.fadeShow"
        :webp="$attrs.webp"
        :show-menu-by-longpress="$attrs.showMenuByLongpress"
        :draggable="$attrs.draggable"
        :src="isErrorState ? failedImage : (src || defaultImage)"
        @loadstart="isLoadState = true"
        @load="isLoadState = false"
        @error="isErrorState = true; isLoadState = false"
      />
      <view v-if="showFailed && isErrorState && !failedImage" class="inner-view error">
        <Icon icon="warning" color="text.second" :size="32" noError />
        <Text v-if="realWidth > 50" color="text.second" :text="src ? '加载失败' : '暂无图片'" :fontSize="22" />
      </view>
      <view v-if="showLoading && isLoadState" class="inner-view loading">
        <ActivityIndicator
          :color="themeContext.resolveThemeColor(loadingColor)"
          :size="themeContext.resolveThemeSize(loadingSize)"
        />
      </view>
    </template>
    <slot v-if="!src && !defaultImage" name="empty"></slot>
    <slot />
  </view>
</template>

<script setup lang="ts">
import { computed, getCurrentInstance, nextTick, onMounted, ref, watch } from 'vue';
import { propGetThemeVar, useTheme } from '../theme/ThemeDefine';
import ActivityIndicator from './ActivityIndicator.vue';
import Text from './Text.vue';
import Icon from './Icon.vue';
import { RandomUtils } from '@imengyu/imengyu-utils';

export interface ImageProps {
  /**
   * 图片地址
   */
  src?: string,
  /**
   * 加载失败图片地址
   */
  failedImage?: string,
  /**
   * 为空时图片地址
   */
  defaultImage?: string,
  /**
   * 是否显示加载中提示，默认是
   */
  showLoading?: boolean,
  /**
   * 是否显示加载失败提示，默认是
   */
  showFailed?: boolean,
  /**
   * 是否显示灰色占位，默认是
   */
  showGrey?: boolean,
  /**
   * 在填充模式下是否显示背景模糊样式，默认是
   */
  showBackgroundEffect?: boolean,
  width?: string|number,
  height?: string|number,
  /**
   * 是否可以点击预览图片
   */
  clickPreview?: boolean,
  /**
   * 初始加载中状态
   */
  loading?: boolean,
  /**
   * 加载中圆圈颜色
   */
  loadingColor?: string,
  /**
   * 加载中圆圈颜色
   */
  loadingSize?: string|number,
  /**
   * 指定图片是否可以点击，默认否
   */
  touchable?: boolean,
  /**
   * 图片是否有圆型（50%圆角）
   * @default false
   */
  round?: boolean,
  /**
   * 圆角大小
   * @default 0
   */
  radius?: string|number,

  borderImageSlice?: number,
  borderImageRepeat?: 'stretch' | 'repeat' | 'round',
  borderImageWidth?: number,

  /**
   * 内部样式
   */
  innerStyle?: object;
  mode?: 'aspectFill' | 'aspectFit' | 'widthFix' | 'heightFix' | 'top' | 'bottom' | 'left' | 'right' | 'center' | 'borderImage',
  innerClass?: string,
}

const id = 'img' + RandomUtils.genNonDuplicateID(20);

defineOptions({
  options: {
    virtualHost: true
  }
})
const props = withDefaults(defineProps<ImageProps>(), {
  src: '',
  failedImage: () => propGetThemeVar('ImageFailedImage', ''),
  defaultImage: () => propGetThemeVar('ImageDefaultImage', ''),
  showLoading: () => propGetThemeVar('ImageShowLoading', true),
  showFailed: () => propGetThemeVar('ImageShowFailed', true),
  showGrey: () => propGetThemeVar('ImageShowGrey', false),
  showBackgroundEffect: () => propGetThemeVar('ImageShowBackgroundEffect', true),
  loading: false,
  loadingColor: () => propGetThemeVar('ImageLoadingColor', 'border.default'),
  loadingSize: () => propGetThemeVar('ImageLoadingSize', 50),
  touchable: false,
  round: () => propGetThemeVar('ImageRound', false),
  radius: () => propGetThemeVar('ImageRadius', ''),
})
const emit = defineEmits([ 'click' ]);
const showBackgroundEffect = computed(() => props.showBackgroundEffect && props.mode === 'aspectFit');


const isErrorState = ref(false);
const isLoadState = ref(true);
const themeContext = useTheme();
const instance = getCurrentInstance();

const style = computed(() => {
  const o : Record<string, any> = {
    borderRadius: props.round ? '50%' : themeContext.resolveThemeSize(props.radius), 
    backgroundColor: isErrorState.value || props.showGrey ? themeContext.resolveThemeColor('background.imageBox') : 'transparent',
    overflow: 'hidden',
    width: themeContext.resolveThemeSize(props.width),
    height: themeContext.resolveThemeSize(props.height),
    ...props.innerStyle,
  }
  if (props.mode === 'borderImage') {
    o.borderImageSource = `url('${props.src || props.defaultImage}')`;
    o.borderImageSlice = props.borderImageSlice;
    o.borderImageRepeat = props.borderImageRepeat;
    o.borderImageWidth = props.borderImageWidth;
  }
  return o;
});
const backgroundEffectStyle = computed(() => ({
  position: 'absolute',
  left: 0,
  right: 0,
  top: 0,
  bottom: 0,
  zIndex: 1,
  backgroundPosition: 'center',
  backgroundSize: 'cover',
  backgroundImage: `url('${props.src || props.defaultImage}')`,
  filter: 'blur(3px)',
}))
const backgroundEffectStyle2 = computed(() => ({
  position: 'absolute',
  left: 0,
  right: 0,
  top: 0,
  bottom: 0,
  zIndex: 1,
  backgroundRepeat: 'no-repeat',
  backgroundPosition: 'center',
  backgroundSize: 'contain',
  backgroundImage: `url('${props.src || props.defaultImage}')`,
}))
const realWidth = ref(0);

function precentOrFull(value: string|number) {
  if (typeof value === 'number')
    return value;
  if (typeof value === 'string' && value.endsWith('%'))
    return '100%';
  return value;
}

function handleClick() {
  if (props.clickPreview) {
    uni.previewImage({
      urls: [ props.src ],
    })
  }
  if (props.touchable)
    emit('click');
}
function loadSrcState() {
  if (props.src || props.defaultImage) {
    isErrorState.value = false;
    isLoadState.value = true;
  } else {
    isErrorState.value = true;
    isLoadState.value = false;
  }
}
function measureImage() {
  uni.createSelectorQuery()
    .in(instance)
    .select('#' + id)
    .boundingClientRect((rect) => {
      if (rect)
        realWidth.value = (rect as UniApp.NodeInfo).width || 0;
    }).exec();
}

watch(() => props.src, (newVal, oldVal) => {
  if (!newVal && !props.defaultImage) {
    isErrorState.value = true;
    isLoadState.value = false;
  } else
    isErrorState.value = false;
  nextTick(() => {
    measureImage();
  });
})

onMounted(() => {
  loadSrcState();
  nextTick(() => {
    measureImage();
  })
})
</script>

<style lang="scss">
.nana-image-wrapper {
  position: relative;
  flex-shrink: 0;

  .inner-view {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
  }
}
</style>