<template>
  <div
    ref="containerRef"
    :class="[ns.b(), { [ns.m('fullscreen')]: fullScreen }]"
    :style="containerStyle"
  >
    <slot />
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount, watch, nextTick } from "vue";
import { watermarkProps } from "./watermark";
import { useNamespace } from "@yh-ui/hooks";
import { useComponentTheme } from "@yh-ui/theme";
defineOptions({
  name: "YhWatermark"
});
const props = defineProps(watermarkProps);
const ns = useNamespace("watermark");
const DEFAULT_FONT = {
  color: "rgba(0,0,0,0.15)",
  fontSize: 16,
  fontWeight: "normal",
  fontFamily: "sans-serif",
  fontStyle: "normal",
  textAlign: "center",
  lineHeight: 22
};
const { themeStyle } = useComponentTheme(
  "watermark",
  computed(() => props.themeOverrides)
);
const isDark = ref(false);
let darkObserver = null;
const mergedFont = computed(() => {
  const defaultColor = isDark.value ? "rgba(255, 255, 255, 0.15)" : "rgba(0,0,0,0.15)";
  return {
    ...DEFAULT_FONT,
    color: defaultColor,
    ...props.font || {}
  };
});
const containerRef = ref(null);
let watermarkRef = null;
const watermarkUrl = ref("");
const containerStyle = computed(() => {
  return {
    ...themeStyle.value,
    position: "relative",
    overflow: "hidden"
  };
});
const watermarkInnerStyle = computed(() => {
  const isGlobalRotated = props.globalRotate !== 0;
  const size = isGlobalRotated ? "150%" : "100%";
  const offset = isGlobalRotated ? "-25%" : "0";
  return {
    position: props.fullScreen ? "fixed" : "absolute",
    top: offset,
    left: offset,
    width: size,
    height: size,
    zIndex: props.zIndex,
    pointerEvents: "none",
    backgroundRepeat: "repeat",
    backgroundImage: `url(${watermarkUrl.value})`,
    backgroundSize: `${props.gap[0] + props.width}px ${props.gap[1] + props.height}px`,
    backgroundPosition: `${props.offset[0]}px ${props.offset[1]}px`,
    visibility: "visible",
    opacity: 1,
    display: "block",
    transform: `rotate(${props.globalRotate}deg)`,
    transformOrigin: "center center"
  };
});
const renderWatermark = () => {
  if (typeof document === "undefined") return;
  const canvas = document.createElement("canvas");
  const ratio = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
  const canvasWidth = props.width + props.gap[0];
  const canvasHeight = props.height + props.gap[1];
  canvas.width = canvasWidth * ratio;
  canvas.height = canvasHeight * ratio;
  const ctx = canvas.getContext("2d");
  if (!ctx) return;
  ctx.scale(ratio, ratio);
  ctx.translate(canvasWidth / 2, canvasHeight / 2);
  ctx.rotate(props.rotate * Math.PI / 180);
  if (props.image) {
    const img = new Image();
    img.crossOrigin = "anonymous";
    img.referrerPolicy = "no-referrer";
    img.src = props.image;
    img.onload = () => {
      ctx.drawImage(img, -props.width / 2, -props.height / 2, props.width, props.height);
      watermarkUrl.value = canvas.toDataURL();
      createOrUpdateWatermark();
    };
  } else {
    const { color, fontSize, fontWeight, fontFamily, fontStyle, textAlign, lineHeight } = mergedFont.value;
    ctx.fillStyle = color || "rgba(0,0,0,0.15)";
    ctx.font = `${fontStyle} ${fontWeight} ${typeof fontSize === "number" ? fontSize + "px" : fontSize} ${fontFamily}`;
    ctx.textAlign = textAlign || "center";
    ctx.textBaseline = "middle";
    const contents = Array.isArray(props.content) ? props.content : typeof props.content === "string" ? props.content.split("\n") : [props.content];
    const lH = lineHeight || 22;
    contents.forEach((text, index) => {
      const yOffset = (index - (contents.length - 1) / 2) * lH;
      ctx.fillText(text, 0, yOffset);
    });
    watermarkUrl.value = canvas.toDataURL();
    createOrUpdateWatermark();
  }
};
const createOrUpdateWatermark = () => {
  if (typeof document === "undefined" || !containerRef.value) return;
  if (watermarkRef && watermarkRef.parentNode) {
    watermarkRef.parentNode.removeChild(watermarkRef);
  }
  const div = document.createElement("div");
  const style = watermarkInnerStyle.value;
  Object.assign(div.style, style);
  if (style.zIndex !== void 0) {
    div.style.zIndex = style.zIndex.toString();
  }
  div.className = `yh-wm-${Math.random().toString(36).slice(2, 9)}`;
  watermarkRef = div;
  containerRef.value.appendChild(div);
};
let observer = null;
let checkTimer = null;
const initGuard = () => {
  if (!props.antiTamper || !containerRef.value) return;
  if (observer) observer.disconnect();
  observer = new MutationObserver((mutations) => {
    for (const mutation of mutations) {
      if (mutation.type === "childList") {
        const removed = Array.from(mutation.removedNodes);
        if (removed.includes(watermarkRef)) {
          createOrUpdateWatermark();
        }
      } else if (mutation.type === "attributes" && mutation.target === watermarkRef) {
        createOrUpdateWatermark();
      }
    }
  });
  observer.observe(containerRef.value, {
    attributes: true,
    childList: true,
    subtree: true,
    attributeFilter: ["style", "class", "hidden"]
  });
  if (checkTimer) clearInterval(checkTimer);
  checkTimer = setInterval(() => {
    if (!watermarkRef || !watermarkRef.parentNode || watermarkRef.style.display === "none") {
      createOrUpdateWatermark();
    }
  }, 3e3);
};
watch(
  () => [
    props.content,
    props.image,
    props.width,
    props.height,
    props.gap,
    props.rotate,
    props.globalRotate,
    props.zIndex,
    props.fullScreen,
    props.font
  ],
  () => {
    renderWatermark();
  },
  { deep: true }
);
onMounted(() => {
  if (typeof document !== "undefined") {
    isDark.value = document.documentElement.classList.contains("dark");
    darkObserver = new MutationObserver(() => {
      const nextDark = document.documentElement.classList.contains("dark");
      if (nextDark !== isDark.value) {
        isDark.value = nextDark;
        renderWatermark();
      }
    });
    darkObserver.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
  }
  renderWatermark();
  nextTick(() => {
    initGuard();
  });
});
onBeforeUnmount(() => {
  if (checkTimer) {
    clearInterval(checkTimer);
    checkTimer = null;
  }
  if (observer) {
    observer.disconnect();
    observer = null;
  }
  if (darkObserver) {
    darkObserver.disconnect();
    darkObserver = null;
  }
  if (watermarkRef && watermarkRef.parentNode) {
    watermarkRef.parentNode.removeChild(watermarkRef);
  }
});
defineExpose({
  renderWatermark
});
</script>

<style>
@charset "UTF-8";
/**
 * YH-UI Sass Variables
 * 原具体的 CSS 变量输出规则 (:root, html.dark 等) 已移至 root.scss，以防止各组件样式编译时产生重复的全局变量 CSS 冗余。
 */
.yh-watermark {
  position: var(--yh-watermark-container-position, relative);
  width: var(--yh-watermark-width, 100%);
  height: var(--yh-watermark-height, 100%);
}
.yh-watermark--fullscreen {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: var(--yh-watermark-fullscreen-z-index, 9999);
}
</style>
