<script setup>
import { computed, ref, onMounted, onUnmounted, watch } from "vue";
import { useNamespace, useLocale } from "@yh-ui/hooks";
import { imageViewerProps, imageViewerEmits } from "./image-viewer";
import { loadViewer } from "../../viewerjs";
defineOptions({
  name: "YhImageViewer"
});
const props = defineProps(imageViewerProps);
const emit = defineEmits(imageViewerEmits);
const ns = useNamespace("viewer");
const { t } = useLocale();
const index = ref(props.initialIndex);
const scale = ref(1);
const rotate = ref(0);
let viewer = null;
let viewerList = null;
const transform = computed(() => {
  return `scale(${scale.value}) rotate(${rotate.value}deg)`;
});
const handleClose = () => {
  emit("close");
};
const initViewerJS = async () => {
  if (typeof document === "undefined") return;
  let ViewerClass;
  try {
    ViewerClass = await loadViewer();
  } catch {
    return;
  }
  const list = document.createElement("div");
  list.style.display = "none";
  props.urlList.forEach((src) => {
    const img = document.createElement("img");
    img.src = src;
    list.appendChild(img);
  });
  document.body.appendChild(list);
  viewerList = list;
  const nextViewer = new ViewerClass(list, {
    ...props.viewerOptions,
    initialViewIndex: props.initialIndex,
    hidden: () => {
      if (viewerList && typeof document !== "undefined") {
        document.body.removeChild(viewerList);
        viewerList = null;
      }
      viewer?.destroy();
      viewer = null;
      emit("close");
    }
  });
  viewer = nextViewer;
  nextViewer.show();
};
const handlePrev = () => {
  const len = props.urlList.length;
  if (len <= 1) return;
  if (index.value > 0) {
    index.value--;
  } else if (props.infinite) {
    index.value = len - 1;
  }
};
const handleNext = () => {
  const len = props.urlList.length;
  if (len <= 1) return;
  if (index.value < len - 1) {
    index.value++;
  } else if (props.infinite) {
    index.value = 0;
  }
};
const handleZoomIn = () => {
  scale.value *= props.zoomRate;
};
const handleZoomOut = () => {
  scale.value /= props.zoomRate;
};
const handleRotateLeft = () => {
  rotate.value -= 90;
};
const handleRotateRight = () => {
  rotate.value += 90;
};
const reset = () => {
  scale.value = 1;
  rotate.value = 0;
};
watch(index, (val) => {
  reset();
  emit("switch", val);
});
watch(
  () => props.initialIndex,
  (val) => {
    index.value = val;
  }
);
watch(
  () => props.urlList,
  async () => {
    if (props.viewerMode === "viewerjs") {
      if (viewer) {
        viewer.destroy();
        viewer = null;
      }
      if (typeof document !== "undefined" && viewerList) {
        document.body.removeChild(viewerList);
        viewerList = null;
      }
      await initViewerJS();
    }
  },
  { deep: true }
);
const handleKeyDown = (e) => {
  if (props.viewerMode === "viewerjs") return;
  if (e.key === "Escape" && props.closeOnPressEscape) {
    handleClose();
  } else if (e.key === "ArrowLeft") {
    handlePrev();
  } else if (e.key === "ArrowRight") {
    handleNext();
  } else if (e.key === "ArrowUp") {
    handleZoomIn();
  } else if (e.key === "ArrowDown") {
    handleZoomOut();
  }
};
onMounted(async () => {
  if (typeof window !== "undefined") {
    if (props.viewerMode === "viewerjs") {
      await initViewerJS();
    } else {
      window.addEventListener("keydown", handleKeyDown);
    }
  }
});
onUnmounted(() => {
  if (typeof window !== "undefined") {
    window.removeEventListener("keydown", handleKeyDown);
  }
  if (viewer) {
    viewer.destroy();
    viewer = null;
  }
  if (typeof document !== "undefined" && viewerList) {
    document.body.removeChild(viewerList);
    viewerList = null;
  }
});
defineExpose({
  prev: handlePrev,
  next: handleNext,
  zoomIn: handleZoomIn,
  zoomOut: handleZoomOut,
  rotateLeft: handleRotateLeft,
  rotateRight: handleRotateRight,
  reset
});
</script>

<template>
  <Teleport to="body" :disabled="!teleported">
    <div v-if="viewerMode !== 'viewerjs'" :class="ns.b()" :style="{
  zIndex
}">
      <div :class="ns.e('mask')" @click="hideOnClickModal && handleClose()"></div>

      <!-- Close -->
      <span
        :class="[ns.e('btn'), ns.e('close')]"
        :title="t('imageviewer.close')"
        :aria-label="t('imageviewer.close')"
        @click="handleClose"
      >
        <svg viewBox="0 0 1024 1024" width="1em" height="1em">
          <path
            fill="currentColor"
            d="M512 456.2L794.8 173.4l55.8 55.8L567.8 512l282.8 282.8-55.8 55.8L512 567.8 229.2 850.6l-55.8-55.8L456.2 512 173.4 229.2l55.8-55.8L512 456.2z"
          />
        </svg>
      </span>

      <!-- Arrows -->
      <template v-if="urlList.length > 1">
        <span
          :class="[ns.e('btn'), ns.e('prev')]"
          :title="t('imageviewer.prev')"
          :aria-label="t('imageviewer.prev')"
          @click="handlePrev"
        >
          <svg viewBox="0 0 1024 1024" width="1em" height="1em">
            <path
              fill="currentColor"
              d="M609.4 824.6L296.8 512l312.6-312.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L228.9 489.4c-12.5 12.5-12.5 32.8 0 45.3l335.2 335.2c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3z"
            />
          </svg>
        </span>
        <span
          :class="[ns.e('btn'), ns.e('next')]"
          :title="t('imageviewer.next')"
          :aria-label="t('imageviewer.next')"
          @click="handleNext"
        >
          <svg viewBox="0 0 1024 1024" width="1em" height="1em">
            <path
              fill="currentColor"
              d="M414.6 824.6l312.6-312.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L346.7 802.1c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L727.2 512 414.6 199.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l335.2 335.2c12.5 12.5 12.5 32.8 0 45.3L369.3 915.1c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0z"
            />
          </svg>
        </span>
      </template>

      <!-- Actions -->
      <div v-if="showProgress" :class="ns.e('actions')">
        <div :class="ns.e('actions-inner')">
          <i
            :class="ns.e('zoom-out')"
            :title="t('imageviewer.zoomOut')"
            :aria-label="t('imageviewer.zoomOut')"
            @click="handleZoomOut"
            ><svg viewBox="0 0 1024 1024" width="1em" height="1em">
              <path fill="currentColor" d="M192 480h640v64H192z" /></svg
          ></i>
          <i
            :class="ns.e('zoom-in')"
            :title="t('imageviewer.zoomIn')"
            :aria-label="t('imageviewer.zoomIn')"
            @click="handleZoomIn"
            ><svg viewBox="0 0 1024 1024" width="1em" height="1em">
              <path
                fill="currentColor"
                d="M480 480V224h64v256h256v64H544v256h-64V544H224v-64h256z"
              /></svg
          ></i>
          <i
            :class="ns.e('reset')"
            :title="t('imageviewer.reset')"
            :aria-label="t('imageviewer.reset')"
            @click="reset"
            ><svg viewBox="0 0 1024 1024" width="1em" height="1em">
              <path
                fill="currentColor"
                d="M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896zm0 64a384 384 0 1 0 0 768 384 384 0 0 0 0-768zm0 128a256 256 0 1 1 0 512 256 256 0 0 1 0-512z"
              /></svg
          ></i>
          <i
            :class="ns.e('rotate-left')"
            :title="t('imageviewer.rotateLeft')"
            :aria-label="t('imageviewer.rotateLeft')"
            @click="handleRotateLeft"
          >
            <svg viewBox="0 0 1024 1024" width="1em" height="1em">
              <path
                fill="currentColor"
                d="M512 128c-212.1 0-384 171.9-384 384s171.9 384 384 384 384-171.9 384-384h-64c0 176.7-143.3 320-320 320s-320-143.3-320-320 143.3-320 320-320v64l192-128-192-128v64z"
              />
            </svg>
          </i>
          <i
            :class="ns.e('rotate-right')"
            :title="t('imageviewer.rotateRight')"
            :aria-label="t('imageviewer.rotateRight')"
            @click="handleRotateRight"
          >
            <svg viewBox="0 0 1024 1024" width="1em" height="1em">
              <path
                fill="currentColor"
                d="M512 128V64L320 192l192 128v-64c176.7 0 320 143.3 320 320s-143.3 320-320 320-320-143.3-320-320h-64c0 212.1 171.9 384 384 384s384-171.9 384-384-171.9-384-384-384z"
              />
            </svg>
          </i>
        </div>
      </div>

      <!-- Canvas -->
      <div :class="ns.e('canvas')">
        <img :src="urlList[index]" :class="ns.e('img')" :style="{
  transform
}" />
      </div>
    </div>
  </Teleport>
</template>

<style>
@charset "UTF-8";
/**
 * YH-UI Sass Variables
 * 原具体的 CSS 变量输出规则 (:root, html.dark 等) 已移至 root.scss，以防止各组件样式编译时产生重复的全局变量 CSS 冗余。
 */
.yh-image {
  position: relative;
  display: inline-block;
  overflow: hidden;
  vertical-align: middle;
}
.yh-image__inner {
  width: 100%;
  height: 100%;
  vertical-align: top;
}
.yh-image__inner.is-preview {
  cursor: pointer;
}

.yh-image__placeholder {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  background-color: var(--yh-image-placeholder-bg-color);
  color: var(--yh-image-placeholder-text-color);
  font-size: 14px;
  vertical-align: middle;
}

.yh-image__error {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  background-color: var(--yh-image-error-bg-color);
  color: var(--yh-image-error-text-color);
  font-size: 14px;
  vertical-align: middle;
}

.yh-viewer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  justify-content: center;
  align-items: center;
}
.yh-viewer__mask {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  background: var(--yh-image-viewer-mask-bg-color);
}

.yh-viewer__btn {
  position: absolute;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  opacity: 0.8;
  cursor: pointer;
  box-sizing: border-box;
  user-select: none;
  color: var(--yh-image-viewer-btn-color);
  background-color: var(--yh-image-viewer-btn-bg-color);
  border: none;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.yh-viewer__btn:hover {
  opacity: 1;
  transform: scale(1.1);
  background-color: var(--yh-image-viewer-btn-hover-bg-color);
}

.yh-viewer__close {
  top: 40px;
  right: 40px;
  width: 44px;
  height: 44px;
  font-size: 24px;
}

.yh-viewer__prev {
  top: 50%;
  left: 40px;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  font-size: 24px;
  background-color: var(--yh-image-viewer-btn-bg-color);
  border: 1px solid rgba(255, 255, 255, 0.2);
}

.yh-viewer__next {
  top: 50%;
  right: 40px;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  font-size: 24px;
  background-color: var(--yh-image-viewer-btn-bg-color);
  border: 1px solid rgba(255, 255, 255, 0.2);
}

.yh-viewer__actions {
  position: absolute;
  z-index: 10;
  left: 50%;
  bottom: 30px;
  transform: translateX(-50%);
  width: 282px;
  height: 44px;
  padding: 0 23px;
  background-color: var(--yh-image-viewer-btn-bg-color);
  backdrop-filter: blur(4px);
  border-radius: 22px;
  display: flex;
  align-items: center;
  justify-content: space-around;
}

.yh-viewer__actions-inner {
  width: 100%;
  display: flex;
  justify-content: space-around;
  align-items: center;
  color: var(--yh-image-viewer-btn-color);
  font-size: 20px;
}
.yh-viewer__actions-inner i {
  cursor: pointer;
  display: flex;
  transition: color 0.2s;
}
.yh-viewer__actions-inner i:hover {
  color: var(--yh-color-primary);
}

.yh-viewer__canvas {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1;
}

.yh-viewer__img {
  max-width: 90%;
  max-height: 90%;
  transition: transform 0.3s cubic-bezier(0.21, 0.6, 0.35, 1);
  user-select: none;
  -webkit-user-drag: none;
}
</style>
