<template>
	<view class="cl-watermark" :class="[pt.className]">
		<view class="cl-watermark__content" :class="[pt.container?.className]">
			<slot></slot>
		</view>

		<canvas
			ref="canvasRef"
			type="2d"
			:canvas-id="canvasId"
			:id="canvasId"
			class="cl-watermark__canvas"
			:style="{
				width: containerWidth + 'px',
				height: containerHeight + 'px',
				zIndex
			}"
		></canvas>
	</view>
</template>

<script lang="ts" setup>
import {
	ref,
	computed,
	onMounted,
	watch,
	getCurrentInstance,
	nextTick,
	shallowRef,
	onUnmounted
} from "vue";
import { getDevicePixelRatio, isDark, parsePt, uuid } from "@/.cool";
import type { PassThroughProps } from "../../types";

defineOptions({
	name: "cl-watermark"
});

const props = defineProps({
	// 透传样式
	pt: {
		type: Object,
		default: () => ({})
	},
	// 水印文本
	text: {
		type: String,
		default: "Watermark"
	},
	// 水印字体大小
	fontSize: {
		type: Number,
		default: 16
	},
	// 水印文字颜色(浅色模式)
	color: {
		type: String,
		default: "rgba(0, 0, 0, 0.15)"
	},
	// 水印文字颜色(深色模式)
	darkColor: {
		type: String,
		default: "rgba(255, 255, 255, 0.15)"
	},
	// 水印透明度
	opacity: {
		type: Number,
		default: 1
	},
	// 水印旋转角度
	rotate: {
		type: Number,
		default: -22
	},
	// 水印宽度
	width: {
		type: Number,
		default: 120
	},
	// 水印高度
	height: {
		type: Number,
		default: 64
	},
	// 水印之间的水平间距
	gapX: {
		type: Number,
		default: 100
	},
	// 水印之间的垂直间距
	gapY: {
		type: Number,
		default: 100
	},
	// 水印层级
	zIndex: {
		type: Number,
		default: 9
	},
	// 字体粗细
	fontWeight: {
		type: String,
		default: "normal"
	},
	// 字体样式
	fontFamily: {
		type: String,
		default: "sans-serif"
	}
});

// 透传样式类型定义
type PassThrough = {
	className?: string;
	container?: PassThroughProps;
};

// 解析透传样式配置
const pt = computed(() => parsePt<PassThrough>(props.pt));

// 获取当前实例
const { proxy } = getCurrentInstance()!;

// 创建canvas实例
const canvasRef = shallowRef<UniElement | null>(null);
// 创建canvas ID
const canvasId = `cl-watermark-${uuid()}`;

// 容器高度
const containerWidth = ref(0);

// 容器宽度
const containerHeight = ref(0);

// 计算当前水印颜色
const currentColor = computed(() => {
	if (isDark.value) {
		return props.darkColor;
	}
	return props.color;
});

/**
 * 获取容器尺寸
 */
function getContainerSize(): Promise<void> {
	return new Promise((resolve) => {
		uni.createSelectorQuery()
			.in(proxy)
			.select(".cl-watermark")
			.boundingClientRect((rect) => {
				containerHeight.value = (rect as NodeInfo).height ?? 0;
				containerWidth.value = (rect as NodeInfo).width ?? 0;

				resolve();
			})
			.exec();
	});
}

/**
 * 绘制水印 - 使用Canvas
 */
async function drawWatermark() {
	// 等待渲染完成
	await nextTick();

	// 获取容器尺寸
	await getContainerSize();

	// 等待渲染完成
	await nextTick();

	if (containerWidth.value <= 0 || containerHeight.value <= 0) return;

	uni.createCanvasContextAsync({
		id: canvasId,
		component: proxy,
		success: (canvasContext: CanvasContext) => {
			const drawCtx = canvasContext.getContext("2d")!;

			// 设置canvas尺寸
			drawCtx.canvas.width = containerWidth.value;
			drawCtx.canvas.height = containerHeight.value;

			// 清空画布
			// #ifdef APP
			drawCtx.reset();
			// #endif
			drawCtx.clearRect(0, 0, containerWidth.value, containerHeight.value);

			// 缩放画布以适配高分屏
			// #ifdef APP
			const ratio = getDevicePixelRatio();
			drawCtx.scale(ratio, ratio);
			// #endif

			// 设置全局透明度
			drawCtx.globalAlpha = props.opacity;

			// 设置字体
			drawCtx.font = `${props.fontWeight} ${props.fontSize}px ${props.fontFamily}`;
			drawCtx.fillStyle = currentColor.value;
			drawCtx.textAlign = "center";
			drawCtx.textBaseline = "middle";

			// 计算水印单元的总宽高（包含间距）
			const cellWidth = props.width + props.gapX;
			const cellHeight = props.height + props.gapY;

			// 计算需要多少行和列
			const cols = Math.ceil(containerWidth.value / cellWidth) + 1;
			const rows = Math.ceil(containerHeight.value / cellHeight) + 1;

			// 遍历绘制水印
			for (let row = 0; row < rows; row++) {
				for (let col = 0; col < cols; col++) {
					const x = col * cellWidth + props.width / 2;
					const y = row * cellHeight + props.height / 2;

					drawCtx.save();
					drawCtx.translate(x, y);
					drawCtx.rotate((props.rotate * Math.PI) / 180);
					drawCtx.fillText(props.text, 0, 0);
					drawCtx.restore();
				}
			}
		}
	});
}

// 监听深色模式变化
const stopWatchDark = watch(isDark, () => {
	drawWatermark();
});

// 监听属性变化
const stopWatchProps = watch(
	computed(() => [
		props.text,
		props.fontSize,
		props.color,
		props.darkColor,
		props.opacity,
		props.rotate,
		props.width,
		props.height,
		props.gapX,
		props.gapY,
		props.fontWeight,
		props.fontFamily
	]),
	() => {
		drawWatermark();
	}
);

onMounted(() => {
	drawWatermark();
});

onUnmounted(() => {
	stopWatchDark();
	stopWatchProps();
});

defineExpose({
	refresh: drawWatermark
});
</script>

<style lang="scss" scoped>
.cl-watermark {
	@apply relative w-full h-full;

	&__content {
		@apply relative w-full h-full;
		z-index: 1;
	}

	&__canvas {
		@apply absolute top-0 left-0 pointer-events-none;
	}
}
</style>
