<template>
	<div v-if="showPanel" class="crop-image-overlay" @click.self="close">
		<div class="crop-image-modal">
			<div class="modal-header">
				<h3>{{ $t("Canvas.cropImage") }}</h3>
				<button class="close-btn" @click="close">&times;</button>
			</div>

			<div class="modal-content">
				<!-- 图片剪切 -->
				<div class="image-clip" ref="el" v-if="data.url">
					<div
						class="box"
						ref="box"
						:style="{
							width: clipData.img_width + 'px',
							height: clipData.img_height + 'px',
						}"
					>
						<img :src="data.url" />
						<div class="shade"></div>
						<div
							ref="clipRef"
							class="clip"
							:style="{
								top: clipData.top + 'px',
								left: clipData.left + 'px',
								width: clipData.width + 'px',
								height: clipData.height + 'px',
							}"
							@mousedown.stop="clipMousedown"
							@touchstart.stop="clipMousedown"
						>
							<div class="img">
								<img
									:src="data.url"
									:style="{
										width: clipData.img_width + 'px',
										height: clipData.img_height + 'px',
										top: -clipData.top + 'px',
										left: -clipData.left + 'px',
									}"
								/>
							</div>
							<div
								class="top"
								@mousedown.stop="topMousedown"
								@touchstart.stop="topMousedown"
							></div>
							<div
								class="right"
								@mousedown.stop="rightMousedown"
								@touchstart.stop="rightMousedown"
							></div>
							<div
								class="bottom"
								@mousedown.stop="bottomMousedown"
								@touchstart.stop="bottomMousedown"
							></div>
							<div
								class="left"
								@mousedown.stop="leftMousedown"
								@touchstart.stop="leftMousedown"
							></div>
							<span
								class="top"
								@mousedown.stop="topMousedown"
								@touchstart.stop="topMousedown"
							></span>
							<span
								class="right"
								@mousedown.stop="rightMousedown"
								@touchstart.stop="rightMousedown"
							></span>
							<span
								class="bottom"
								@mousedown.stop="bottomMousedown"
								@touchstart.stop="bottomMousedown"
							></span>
							<span
								class="left"
								@mousedown.stop="leftMousedown"
								@touchstart.stop="leftMousedown"
							></span>
						</div>
					</div>
				</div>
				<!-- 空状态 -->
				<div class="empty-state" v-else>
					<div class="empty-icon">📷</div>
					<p>{{ $t("Canvas.NoPicture") }}</p>
				</div>
			</div>

			<div class="modal-footer">
				<div class="image-count"></div>
				<div class="image-submit gallery_btn" @click="confirm">
					{{ $t("Canvas.confirm") }}
				</div>
			</div>
		</div>
	</div>
</template>

<script setup lang="ts">
	import {
		ref,
		computed,
		defineProps,
		onDeactivated,
		reactive,
		onMounted,
		defineExpose,
	} from "vue";
	import { useI18n } from "vue-i18n";

	// Props
	const props = defineProps([]);
	const { t } = useI18n();
	var resolveFn: (value: string | PromiseLike<string>) => void;
	const showPanel = ref(false);
	const open = (url: string) => {
		showPanel.value = true;
		setImgage(url);
		return new Promise((resolve) => (resolveFn = resolve));
	};
	const close = () => {
		showPanel.value = false;
	};
	//提交选中的T图片
	const confirm = () => {
		close();
		const base64 = getImageBase64();
		resolveFn && resolveFn(base64);
	};

	const data = reactive({
		url: "",
	});
	const el = ref();
	const box = ref();
	const clipRef = ref();
	const clipData = reactive({
		top: 0,
		left: 0,
		width: 0,
		height: 0,
		img_width: 0,
		img_height: 0,
	});
	const canvas = document.createElement("canvas");
	const ctx = canvas.getContext("2d");
	const reload = () => {
		if (!el.value) return;
		const size = Math.min(
			1,
			el.value.offsetWidth / canvas.width,
			el.value.offsetHeight / canvas.height
		);
		const width = size * canvas.width;
		const height = size * canvas.height;
		clipData.left = 0;
		clipData.top = 0;
		clipData.width = width;
		clipData.height = height;
		clipData.img_width = width;
		clipData.img_height = height;
	};
	window.addEventListener("resize", reload);
	onDeactivated(() => {
		window.removeEventListener("resize", reload);
	});

	const setImgage = (url: string) => {
		if (!url) return;
		const img = new Image();
		img.src = url;
		data.url = url;
		img.onload = () => {
			const width = img.width;
			const height = img.height;
			canvas.width = width;
			canvas.height = height;
			ctx?.clearRect(0, 0, width, height);
			ctx?.drawImage(img, 0, 0, width, height);
			nextTick(() => reload());
		};
	};
	const canvasImageDataToBase64 = (imageData: any) => {
		// 创建一个临时的canvas元素
		const canvas = document.createElement("canvas");
		canvas.width = imageData.width;
		canvas.height = imageData.height;
		const ctx = canvas.getContext("2d");
		ctx?.putImageData(imageData, 0, 0);
		const dataURL = canvas.toDataURL("image/png");
		return dataURL;
	};
	const base64toFile = (dataurl, filename = "file") => {
		//转换base64
		let arr = dataurl.split(",");
		let mime = arr[0].match(/:(.*?);/)[1];
		let suffix = mime.split("/")[1];
		let bstr = atob(arr[1]);
		let n = bstr.length;
		let u8arr = new Uint8Array(n);
		while (n--) {
			u8arr[n] = bstr.charCodeAt(n);
		}
		return new File([u8arr], `${filename}.${suffix}`, {
			type: mime,
		});
	};
	const getImageBase64 = () => {
		const scale = canvas.width / clipData.img_width;
		const imageData = ctx?.getImageData(
			clipData.left * scale,
			clipData.top * scale,
			clipData.width * scale,
			clipData.height * scale
		);
		const base64 = canvasImageDataToBase64(imageData);
		return base64;
	};
	const getImageFile = () => {
		const base64 = getImageBase64();
		const file = base64toFile(base64, "image.png");
		return file;
	};

	// 移动裁剪框
	const clipMousedown = (e: MouseEvent | TouchEvent) => {
		e.preventDefault();
		var pageX = 0;
		var pageY = 0;
		if (e.type == "touchstart") {
			const touch = e["touches"][0];
			pageX = touch.pageX;
			pageY = touch.pageY;
		} else {
			pageX = e["pageX"];
			pageY = e["pageY"];
		}
		const elInfo = box.value.getBoundingClientRect();
		const clipInfo = clipRef.value.getBoundingClientRect();
		// 鼠标相对元素的位置
		const CX = pageX - clipInfo.x;
		const CY = pageY - clipInfo.y;

		const mousemove = (e: MouseEvent | TouchEvent) => {
			e.preventDefault();
			var pageX = 0;
			var pageY = 0;
			if (e.type == "touchmove") {
				const touch = e["touches"][0];
				pageX = touch.pageX;
				pageY = touch.pageY;
			} else {
				pageX = e["pageX"];
				pageY = e["pageY"];
			}
			let x = pageX - elInfo.x - CX;
			let y = pageY - elInfo.y - CY;
			if (x < 0) {
				x = 0;
			} else if (x > elInfo.width - clipInfo.width) {
				x = elInfo.width - clipInfo.width;
			}
			if (y < 0) {
				y = 0;
			} else if (y > elInfo.height - clipInfo.height) {
				y = elInfo.height - clipInfo.height;
			}

			clipData.top = y;
			clipData.left = x;
			clipData.img_width = elInfo.width;
			clipData.img_height = elInfo.height;
		};
		const mouseup = () => {
			window.removeEventListener("mousemove", mousemove);
			window.removeEventListener("mouseup", mouseup);
			window.removeEventListener("touchmove", mousemove);
			window.removeEventListener("touchend", mouseup);
		};
		if (e.type == "touchstart") {
			window.addEventListener("touchmove", mousemove);
			window.addEventListener("touchend", mouseup);
		} else {
			window.addEventListener("mousemove", mousemove);
			window.addEventListener("mouseup", mouseup);
		}
	};

	// 移动裁剪框的四个边框
	const mousedown = (
		e: MouseEvent | TouchEvent,
		type: "top" | "bottom" | "right" | "left"
	) => {
		const minWidth = 20;
		const minHeight = 20;
		const elInfo = box.value.getBoundingClientRect();
		const R = elInfo.width - clipData.left - clipData.width;
		const B = elInfo.height - clipData.top - clipData.height;

		const mousemove = (e: MouseEvent | TouchEvent) => {
			var x = 0;
			var y = 0;
			if (e.type == "touchmove") {
				const touch = e["touches"][0];
				x = touch.pageX - elInfo.x;
				y = touch.pageY - elInfo.y;
			} else {
				x = e["pageX"] - elInfo.x;
				y = e["pageY"] - elInfo.y;
			}

			if (type == "right") {
				let width = x - clipData.left;
				if (width + clipData.left > elInfo.width) {
					width = elInfo.width - clipData.left;
				}
				if (width < minWidth) width = minWidth;
				clipData.width = width;
			} else if (type == "bottom") {
				let height = y - clipData.top;
				if (height + clipData.top > elInfo.height) {
					height = elInfo.height - clipData.top;
				}
				if (height < minHeight) height = minHeight;
				clipData.height = height;
			} else if (type == "left") {
				let left = x;
				let width = clipData.width;
				if (left < 0) {
					left = 0;
				} else if (left > elInfo.width - R - minWidth) {
					left = elInfo.width - R - minWidth;
				}
				width = elInfo.width - R - left;
				clipData.left = left;
				clipData.width = width;
				clipData.img_width = elInfo.width;
				clipData.img_height = elInfo.height;
			} else if (type == "top") {
				let top = y;
				let height = clipData.height;
				if (top < 0) {
					top = 0;
				} else if (top > elInfo.height - B - minHeight) {
					top = elInfo.height - B - minHeight;
				}
				height = elInfo.height - B - top;
				clipData.top = top;
				clipData.height = height;
				clipData.img_height = elInfo.height;
			}
		};
		const mouseup = () => {
			window.removeEventListener("mousemove", mousemove);
			window.removeEventListener("mouseup", mouseup);
			window.removeEventListener("touchmove", mousemove);
			window.removeEventListener("touchend", mouseup);
		};
		if (e.type == "touchstart") {
			window.addEventListener("touchmove", mousemove);
			window.addEventListener("touchend", mouseup);
		} else {
			window.addEventListener("mousemove", mousemove);
			window.addEventListener("mouseup", mouseup);
		}
	};
	const topMousedown = (e: MouseEvent | TouchEvent) => {
		mousedown(e, "top");
	};
	const rightMousedown = (e: MouseEvent | TouchEvent) => {
		mousedown(e, "right");
	};
	const bottomMousedown = (e: MouseEvent | TouchEvent) => {
		mousedown(e, "bottom");
	};
	const leftMousedown = (e: MouseEvent | TouchEvent) => {
		mousedown(e, "left");
	};
	defineExpose({
		open,
		close,
	});
</script>

<style scoped lang="less">
	/* 弹窗遮罩层 */
	.crop-image-overlay {
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background-color: rgba(255, 255, 255, 0.5);
		backdrop-filter: blur(5px);
		-webkit-backdrop-filter: blur(5px);
		display: flex;
		align-items: center;
		justify-content: center;
		z-index: 1001;
		animation: fadeIn 0.3s ease;
	}

	@keyframes fadeIn {
		from {
			opacity: 0;
		}
		to {
			opacity: 1;
		}
	}

	/* 弹窗主体 */
	.crop-image-modal {
		background-color: #fff;
		border-radius: 12px;
		width: 90%;
		height: 90%;
		overflow: hidden;
		display: flex;
		flex-direction: column;
		box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1), 0 0 0 1px rgba(0, 0, 0, 0.05);
		animation: modalSlideUp 0.3s ease;
	}

	@keyframes modalSlideUp {
		from {
			opacity: 0;
			transform: translateY(20px);
		}
		to {
			opacity: 1;
			transform: translateY(0);
		}
	}

	/* 弹窗头部 */
	.modal-header {
		padding: 16px 20px;
		background-color: rgba(255, 255, 255, 0.8);
		border-bottom: 1px solid rgba(0, 0, 0, 0.05);
		display: flex;
		justify-content: space-between;
		align-items: center;
		flex-shrink: 0;

		h3 {
			margin: 0;
			font-size: 18px;
			color: #333;
			font-weight: 600;
		}
	}

	.close-btn {
		background: none;
		border: none;
		font-size: 24px;
		cursor: pointer;
		color: #666;
		padding: 0;
		line-height: 1;
		opacity: 0.7;
		transition: all 0.2s;
		width: 24px;
		height: 24px;
		display: flex;
		align-items: center;
		justify-content: center;

		&:hover {
			opacity: 1;
			color: #333;
			transform: scale(1.1);
		}
	}

	/* 弹窗内容 */
	.modal-content {
		// padding: 20px;
		overflow: hidden;
		flex: 1;
		background-color: #fff;
		-webkit-overflow-scrolling: touch;
		display: flex;
		background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKAQMAAAC3/F3+AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAGUExURf///9ra2sgNdccAAAARSURBVAjXY2A/wICMfjAgIwB8gwi84a8abQAAAABJRU5ErkJggg==);
	}

	.image-clip {
		user-select: none;
		flex: 1;
		display: flex;
		align-items: center;
		justify-content: center;
		> .box {
			position: relative;
			> img {
				display: block;
				width: 100%;
				height: 100%;
			}
			> .shade {
				position: absolute;
				top: 0;
				left: 0;
				right: 0;
				bottom: 0;
				background-color: rgba(0, 0, 0, 0.5);
			}
			> .clip {
				position: absolute;
				cursor: move;
				outline: 1px solid #39f;

				> * {
					position: absolute;
				}
				> .img {
					pointer-events: none;
					width: 100%;
					height: 100%;
					overflow: hidden;
					> img {
						position: absolute;
						background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKAQMAAAC3/F3+AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAGUExURf///9ra2sgNdccAAAARSURBVAjXY2A/wICMfjAgIwB8gwi84a8abQAAAABJRU5ErkJggg==);
					}
				}

				> .top {
					cursor: n-resize;
				}
				> .bottom {
					cursor: s-resize;
				}
				> .right {
					cursor: e-resize;
				}
				> .left {
					cursor: w-resize;
				}

				--border: 4px;
				--trbl: calc(0px - var(--border) / 2);
				--ball-size: 8px;
				--ball-trbl: calc(0px - var(--ball-size) / 2);
				> div.top {
					top: var(--trbl);
					left: 0;
					right: 0;
					height: var(--border);
				}

				> div.bottom {
					bottom: var(--trbl);
					left: 0;
					right: 0;
					height: var(--border);
				}
				> div.left {
					top: 0;
					left: var(--trbl);
					bottom: 0;
					width: var(--border);
				}
				> div.right {
					top: 0;
					right: var(--trbl);
					bottom: 0;
					width: var(--border);
				}
				> span {
					position: absolute;
					width: var(--ball-size);
					height: var(--ball-size);
					border-radius: 50%;
					background-color: #39f;
				}
				> span.top {
					top: var(--ball-trbl);
					left: 50%;
					transform: translateX(-50%);
				}
				> span.right {
					right: var(--ball-trbl);
					top: 50%;
					transform: translateY(-50%);
				}
				> span.bottom {
					bottom: var(--ball-trbl);
					left: 50%;
					transform: translateX(-50%);
				}
				> span.left {
					left: var(--ball-trbl);
					top: 50%;
					transform: translateY(-50%);
				}
			}
		}
	}

	/* 空状态 */
	.empty-state {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		padding: 60px 20px;
		color: #666;
		min-height: 300px;

		.empty-icon {
			font-size: 48px;
			margin-bottom: 16px;
			opacity: 0.5;
		}

		p {
			font-size: 16px;
			margin: 0;
		}
	}

	/* 弹窗底部 */
	.modal-footer {
		padding: 16px 20px;
		background-color: rgba(255, 255, 255, 0.8);
		border-top: 1px solid rgba(0, 0, 0, 0.05);
		display: flex;
		justify-content: space-between;
		align-items: center;
		flex-shrink: 0;
		> .image-submit {
			font-size: 1.2rem;
			line-height: 4rem;
		}
	}

	.image-count {
		font-size: 14px;
		color: #666;
		font-weight: 500;
	}

	/* 响应式设计 */
	@media screen and (max-width: 1024px) {
		.crop-image-modal {
			width: 95%;
			max-width: 900px;
		}

		.modal-content {
			padding: 16px;
		}

		.modal-header,
		.modal-footer {
			padding: 14px 16px;
		}
	}

	@media screen and (max-width: 640px) {
		.crop-image-modal {
			width: 98%;
			margin: 10px;
			max-height: 90vh;
		}

		.modal-content {
			padding: 12px;
			gap: 16px;
		}

		.modal-header h3 {
			font-size: 16px;
		}

		.image-categories {
			gap: 8px;
			padding-bottom: 8px;
		}

		.category-btn {
			padding: 6px 12px;
			font-size: 13px;
			height: 32px;
		}
	}
</style>
