<template>
	<div class="text-to-hex">
		<canvas 
			ref="canvasRef"
			:width="currentCanvasWidth" 
			:height="currentCanvasHeight"
			class="offscreen-canvas"
		></canvas>
	</div>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue';

// Props 定义
const props = defineProps({
	txts: {
		type: Array,
		default: () => [],
		validator: (value) => value.every(item => typeof item === 'string')
	},
	fontSize: {
		type: Number,
		default: 16,
		validator: (value) => value > 0 && value <= 100
	},
	bgColor: {
		type: String,
		default: "#ffffff"
	},
	color: {
		type: String,
		default: "#000000"
	},
	fontFamily: {
		type: String,
		default: "PingFang SC, Microsoft YaHei, Arial, sans-serif"
	}
});

// 响应式数据
const canvasRef = ref(null);
const currentCanvasWidth = ref(0);
const currentCanvasHeight = ref(0);
let ctx = null;
const canvasWarmed = ref(false);

// 计算属性
const validTxts = computed(() => {
	return props.txts.filter(line => line && line.trim() !== '');
});

// 获取字符实际宽度
const getCharWidth = (char) => {
	if (!ctx) return props.fontSize * 0.6;
	ctx.font = `${props.fontSize}px ${props.fontFamily}`;
	return ctx.measureText(char).width;
};

// 计算整行宽度（精确）
const calcLineWidth = (textLine) => {
	if (!ctx) return textLine.length * props.fontSize * 0.6;
	
	ctx.font = `${props.fontSize}px ${props.fontFamily}`;
	let totalWidth = 0;
	for (let i = 0; i < textLine.length; i++) {
		totalWidth += ctx.measureText(textLine[i]).width;
	}
	return Math.ceil(totalWidth);
};

// 清除Canvas内容
const clearCanvas = () => {
	if (!ctx) return;
	ctx.fillStyle = props.bgColor;
	ctx.fillRect(0, 0, currentCanvasWidth.value, currentCanvasHeight.value);
};

// 预热画布
const warmupCanvas = async () => {
	if (canvasWarmed.value || !ctx) return;
	
	try {
		currentCanvasWidth.value = 16;
		currentCanvasHeight.value = 16;
		
		clearCanvas();
		
		ctx.fillStyle = props.color;
		ctx.font = `${props.fontSize}px ${props.fontFamily}`;
		ctx.textBaseline = 'middle';
		ctx.fillText('测', 0, 8);
		
		// 等待字体加载完成
		await document.fonts.ready;
		
		// 获取像素数据验证画布可用
		const imageData = ctx.getImageData(0, 0, 16, 16);
		if (imageData) {
			canvasWarmed.value = true;
		}
		
		// 额外等待确保字体完全渲染
		await new Promise(resolve => setTimeout(resolve, 100));
	} catch (ex) {
		console.log("画布预热异常:", ex);
		canvasWarmed.value = true;
	}
};

// 像素数据转16进制矩阵
const convertCharToMatrix = (imageData, width, height) => {
	let matrix = [];
	const data = imageData.data;
	
	// 只处理16x16的字符矩阵
	for (let y = 0; y < 16; y++) {
		let byte1 = 0, byte2 = 0;
		
		for (let x = 0; x < 16; x++) {
			// 计算实际像素位置（需要考虑画布可能比16宽）
			let actualX = Math.floor(x * width / 16);
			let actualY = Math.floor(y * height / 16);
			let index = (actualY * width + actualX) * 4;
			
			let red = data[index];
			let green = data[index + 1];
			let blue = data[index + 2];
			
			// 判断是否为非背景色（根据颜色阈值）
			// let isBlack = !(red > 200 && green > 200 && blue > 200);
			let gray = (red + green + blue) / 3;
			let isBlack = gray < 255 ;
			if (x < 8) {
				if (isBlack) {
					byte1 |= 0x80 >> x;
				}
			} else {
				if (isBlack) {
					byte2 |= 0x80 >> (x - 8);
				}
			}
		}
		
		matrix.push('0x' + byte1.toString(16).padStart(2, '0').toUpperCase());
		matrix.push('0x' + byte2.toString(16).padStart(2, '0').toUpperCase());
	}
	
	return matrix;
};

// 绘制单个字符并获取像素数据
const drawChar = async (char) => {
	return new Promise((resolve, reject) => {
		try {
			// 获取字符宽度
			const charWidth = getCharWidth(char);
			const canvasWidth = Math.max(16, Math.ceil(charWidth));
			
			// 调整画布尺寸
			currentCanvasWidth.value = canvasWidth;
			currentCanvasHeight.value = 16;
			
			// 重置画布尺寸
			if (canvasRef.value) {
				canvasRef.value.width = canvasWidth;
				canvasRef.value.height = 16;
			}
			
			// 清空画布
			clearCanvas();
			
			// 绘制字符
			ctx.fillStyle = props.color;
			ctx.font = `${props.fontSize}px ${props.fontFamily}`;
			ctx.textBaseline = 'middle';
			ctx.fillText(char, 0, 8);
			
			// 获取像素数据
			const imageData = ctx.getImageData(0, 0, canvasWidth, 16);
			
			resolve({
				char: char,
				pixelData: imageData,
				width: canvasWidth,
				height: 16
			});
		} catch (err) {
			reject(err);
		}
	});
};

// 绘制文本行并获取所有字符的矩阵数据
const drawLine = async (textLine) => {
	const charMatrices = [];
	
	for (let i = 0; i < textLine.length; i++) {
		const char = textLine[i];
		const result = await drawChar(char);
		const matrix = convertCharToMatrix(result.pixelData, result.width, result.height);
		charMatrices.push(matrix);
	}
	
	return charMatrices;
};

// 主方法：处理所有文本并返回十六进制矩阵数组
const drawAndGetPixels = async () => {
	// 确保画布已预热
	await warmupCanvas();
	
	const result = [];
	
	for (let i = 0; i < validTxts.value.length; i++) {
		const line = validTxts.value[i];
		const lineMatrices = await drawLine(line);
		result.push(lineMatrices);
	}
	
	return result;
};

// 获取单个字符的十六进制矩阵（便捷方法）
const getCharHexMatrix = async (char) => {
	await warmupCanvas();
	const result = await drawChar(char);
	return convertCharToMatrix(result.pixelData, result.width, result.height);
};

// 获取文本行的十六进制矩阵（便捷方法）
const getTextLineHexMatrix = async (textLine) => {
	await warmupCanvas();
	return await drawLine(textLine);
};

// 暴露方法给父组件
defineExpose({
	drawAndGetPixels,
	getCharHexMatrix,
	getTextLineHexMatrix
});

// 生命周期
onMounted(() => {
	if (canvasRef.value) {
		ctx = canvasRef.value.getContext('2d');
	}
});
</script>

<style scoped>
.text-to-hex {
	position: relative;
}

.offscreen-canvas {
	position: fixed;
	left: -9999px;
	top: -9999px;
	visibility: hidden;
	pointer-events: none;
}
</style>