<template>
	<div class="character-relationships">
		<div class="headerBox">
			<span
				v-for="(item, index) in list"
				:key="index"
				class="headerItem"
				:class="{ active: item.value === activeIndex }"
				@click="handleChangeLayout(item.value)"
			>
				<img :src="item.icon" :alt="item.label" />
			</span>
		</div>
		<div class="headerBtnBox">
			<img src="./assets/icon-expand.svg" alt="" class="btn-icon" />
			<img src="./assets/icon-download.svg" alt="" class="btn-icon" />
			<img src="./assets/icon-star.svg" alt="" class="btn-icon" />
		</div>
		<!-- 主要内容，人物关系图 -->
		<div class="mainBox">
			<div class="graph" id="relGraph"></div>
		</div>
	</div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from "vue";
import * as echarts from "echarts";
import {getCharacterGlobalInfo, getCharacterRelation } from "@/api/characterPage/characterPage.js";


import 'default-passive-events';

import { useRoute } from 'vue-router';
const route = useRoute();
const personId = ref(route.query.personId || "Y000064");



// const nodes = [
// 	{
// 		id: "c",
// 		name: "埃隆·马斯克",
// 		category: 0,
// 		symbolSize: 80,
// 		symbol: `image://${Center}`,
// 		label: {
// 			show: true,
// 			position: "bottom",
// 			formatter: "{n|{b}}",
// 			rich: {
// 				n: {
// 					color: "rgba(5,95,194,1)",
// 					fontSize: 24,
// 					fontWeight: 700,
// 					fontFamily: "Microsoft YaHei",
// 					lineHeight: 36
// 				}
// 			}
// 		}
// 	},
// 	// 从三点钟方向顺时针排序
// 	{ id: "n11", name: "贾斯汀・马斯克", category: 1, symbolSize: 80, symbol: `image://${P11}` },
// 	{ id: "n7", name: "杰弗里·凯斯勒", category: 1, symbolSize: 80, symbol: `image://${P7}`, r: 80 },
// 	{ id: "n6", name: "斯科特·贝森特", category: 1, symbolSize: 80, symbol: `image://${P6}` },
// 	{ id: "n9", name: "道格·伯格姆", category: 1, symbolSize: 80, symbol: `image://${P9}` },
// 	{ id: "n12", name: "史蒂夫・尤尔韦松", category: 1, symbolSize: 80, symbol: `image://${PS}` },
// 	{ id: "n5", name: "拉里・埃里森", category: 1, symbolSize: 80, symbol: `image://${P5}`, r: 80 },
// 	{ id: "n8", name: "马尔科·卢比奥", category: 1, symbolSize: 80, symbol: `image://${P8}` },
// 	{ id: "n10", name: "艾拉・埃伦普里斯", category: 1, symbolSize: 80, symbol: `image://${P10}`, r: 80 },
// 	{ id: "n2", name: "詹姆斯・默多克", category: 1, symbolSize: 80, symbol: `image://${P2}` },
// 	{ id: "n1", name: "唐纳德・特朗普", category: 1, symbolSize: 80, symbol: `image://${P1}` },
// 	{ id: "n4", name: "金博尔・马斯克", category: 1, symbolSize: 80, symbol: `image://${P4}` },
// 	{ id: "n3", name: "格温・肖特韦尔", category: 1, symbolSize: 80, symbol: `image://${P3}`, r: 80 }
// ];


// const links = [
// 	{ source: "n11", target: "c", label: { show: true, formatter: "第一任妻子" } },
// 	{ source: "n7", target: "c", label: { show: true, formatter: "风险投资家" } },
// 	{ source: "n6", target: "c", label: { show: true, formatter: "特斯拉董事" } },
// 	{ source: "n9", target: "c", label: { show: true, formatter: "特斯拉董事" } },
// 	{ source: "n12", target: "c", label: { show: true, formatter: "特斯拉董事" } },
// 	{ source: "n5", target: "c", label: { show: true, formatter: "早期重要投资人" } },
// 	{ source: "n8", target: "c", label: { show: true, formatter: "Boring Company 总裁" } },
// 	{ source: "n10", target: "c", label: { show: true, formatter: "特斯拉独立董事" } },
// 	{ source: "n2", target: "c", label: { show: true, formatter: "特斯拉董事" } },
// 	{ source: "n1", target: "c", label: { show: true, formatter: "美国总统" } },
// 	{ source: "n4", target: "c", label: { show: true, formatter: "马斯克弟弟" } },
// 	{ source: "n3", target: "c", label: { show: true, formatter: "SpaceX 总裁" } }
// ];

// 处理图片代理
const getProxyUrl = (url) => {
	if (!url) return "";
	const urlStr = String(url);
	// 排除非 http 开头（相对路径）、已经是代理链接、或者是本地链接
	if (!urlStr.startsWith('http') || urlStr.includes('images.weserv.nl') || urlStr.includes('localhost') || urlStr.includes('127.0.0.1')) {
		return url;
	}
	// 移除协议头 http:// 或 https://
	const cleanUrl = urlStr.replace(/^https?:\/\//i, '');
	return `https://images.weserv.nl/?url=${encodeURIComponent(cleanUrl)}`;
};

// 创建圆形图片的函数
const createCircularImage = (imageUrl, size) => {
	return new Promise((resolve) => {
		if (!imageUrl) { 
			resolve('');
			return;
		}

		const img = new Image();
		img.crossOrigin = 'anonymous';
		
		const onLoadSuccess = () => {
			try {
				const canvas = document.createElement('canvas');
				canvas.width = size;
				canvas.height = size;
				const ctx = canvas.getContext('2d');
				
				// 绘制圆形裁剪区域
				ctx.beginPath();
				ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2);
				ctx.closePath();
				ctx.clip();
				
				// 绘制图片
				ctx.drawImage(img, 0, 0, size, size);
				
				resolve(canvas.toDataURL('image/png'));
			} catch (error) { 
				resolve(imageUrl);
			}
		};

		img.onload = onLoadSuccess;
		img.onerror = () => { 
			// 如果加载失败，尝试不带 crossOrigin 的方式
			const img2 = new Image();
			img2.onload = () => {
				try {
					const canvas = document.createElement('canvas');
					canvas.width = size;
					canvas.height = size;
					const ctx = canvas.getContext('2d');
					
					ctx.beginPath();
					ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2);
					ctx.closePath();
					ctx.clip();
					
					ctx.drawImage(img2, 0, 0, size, size);
					resolve(canvas.toDataURL('image/png'));
				} catch (error) { 
					resolve(imageUrl);
				}
			};
			img2.onerror = () => { 
				resolve(imageUrl);
			};
			img2.src = imageUrl;
		};
		
		img.src = imageUrl;
	});
};

const nodes = ref([]);
const links = ref([]);

// 人物全局信息
const characterInfo = ref({});
	// 人物关系
const CharacterRelation = ref([]);

const getCharacterGlobalInfoFn = async () => {
	const params = {
		personId: personId.value
	};

	try{
		const res = await getCharacterGlobalInfo(params);
		
		if (res.code === 200) {
			if (res.data) {
				characterInfo.value = res.data;
			}
		}

	}catch(error){

	}
	
};

const getCharacterRelationFn = async () => {
	const params = {
		personId: personId.value
	};
		try{
			const res = await getCharacterRelation(params);
			if (res.code === 200) {
				if (res.data) {
					CharacterRelation.value = res.data;
				}
			}
			
			// 创建圆形头像 
			
			const centerImageUrl = getProxyUrl(characterInfo.value.imageUrl); 
			
			const centerCircularImage = await createCircularImage(centerImageUrl, 160); 

		if(CharacterRelation.value.length > 0){
			// 并行创建所有圆形头像
			const circularImages = await Promise.all(
				CharacterRelation.value.map((item) =>
					createCircularImage(getProxyUrl(item.imageUrl), 160)
				)
			);

			const centerNode = {
				id: "c",
				name: characterInfo.value.name,
				category: 0,
				symbolSize: 80,
				symbol: `image://${centerCircularImage}`,
				label: {
					show: true,
					position: "bottom",
					formatter: "{n|{b}}",
					rich: {
						n: {
							color: "rgba(5,95,194,1)",
							fontSize: 24,
							fontWeight: 700,
							fontFamily: "Microsoft YaHei",
							lineHeight: 36
						}
					}
				}
			}

			const newNodes = CharacterRelation.value.map((item,index) => {
				return{
					id: index,
					name: item.name,
					category: 1,
					symbolSize: 80,
					symbol: `image://${circularImages[index]}`
				}
			});

			newNodes.push(centerNode);

			const newLinks = CharacterRelation.value.map((item,index) =>({
				source:index,
				target:"c",
				label: { 
					show: true, 
					formatter: item.relation }
			}));

			nodes.value = newNodes;
			links.value = newLinks;
			
		}else{
			nodes.value = [{
				id: "c",
				name: characterInfo.value.name,
				category: 0,
				symbolSize: 80,
				symbol: `image://${centerCircularImage}`,
				label: {
					show: true,
					position: "bottom",
					formatter: "{n|{b}}",
					rich: {
						n: {
							color: "rgba(5,95,194,1)",
							fontSize: 24,
							fontWeight: 700,
							fontFamily: "Microsoft YaHei",
							lineHeight: 36
						}
					}
				}
			}];
			links.value = [];
		}
		const el = document.getElementById("relGraph");
	if (!el) return;
	chart = echarts.init(el);
	
	const setOption = () => {
		const rect = el.getBoundingClientRect();
		const cx = rect.width / 2;
		const cy = rect.height / 2;
		const radius = Math.min(cx, cy) - 140;

		const dataNodes = nodes.value.map((n, i) => {
			if (n.id === "c") {
				return { ...n, x: cx, y: cy, fixed: true };
			}
			// 均匀环形分布
			const idx = i - 1;
			const angle = (idx / (nodes.value.length - 1)) * Math.PI * 2;
			const rLocal = radius + (n.r || 0);
			const x = cx + rLocal * Math.cos(angle);
			const y = cy + rLocal * Math.sin(angle);
			return { ...n, x, y };
		});

		chart.setOption({
			tooltip: {},
			series: [
				{
					type: "graph",
					layout: activeIndex.value === "圆形布局" ? "none" : "force",
					circular: { rotateLabel: true },
					force: { repulsion: 800, edgeLength: [80, 160] },
					roam: true,
					data: activeIndex.value === "圆形布局" ? dataNodes : nodes.value,
					links: links.value,
					edgeSymbol: ["none", "arrow"],
					edgeSymbolSize: [4, 10],
					lineStyle: { color: "rgba(174,214,255,1)", width: 2, opacity: 0.8 },
					edgeLabel: {
						show: true,
						position: "middle",
						distance: -18,
						formatter: ({ data }) => data?.label?.formatter || "",
						color: "rgb(5, 95, 194)",
						fontSize: 12,
						fontWeight: 400,
						fontFamily: "Microsoft YaHei",
						lineHeight: 24,
						backgroundColor: "rgba(231, 243, 255, 1)",
						borderRadius: 24,
						padding: [0, 12]
					},
					label: { show: true, position: "bottom", color: "rgb(59,65,75)", fontSize: 16 },
					itemStyle: { color: "rgba(5,95,194,1)" },
					emphasis: { focus: "adjacency" }
				}
			]
		});
	};
	setOption();
	

	}catch(error){

	}
	
};

const list = ref([
	{ 
		value: "圆形布局", 
		label: "圆形布局", 
		icon: new URL('./assets/icon-circle.svg', import.meta.url).href,
	},
	{ 
		value: "力导向布局", 
		label: "力导向布局", 
		icon: new URL('./assets/icon-force.svg', import.meta.url).href,
	},
	{ 
		value: "树形布局", 
		label: "树形布局", 
		icon: new URL('./assets/icon-tree.svg', import.meta.url).href,
	},
]);
const activeIndex = ref("圆形布局");

const handleChangeLayout = (layout) => {
	activeIndex.value = layout;
};




let chart;

onMounted(async () => {
	await getCharacterGlobalInfoFn();
	getCharacterRelationFn();
	const el = document.getElementById("relGraph");
	if (!el) return;
	chart = echarts.init(el);
	
	const setOption = () => {
		const rect = el.getBoundingClientRect();
		const cx = rect.width / 2;
		const cy = rect.height / 2;
		const radius = Math.min(cx, cy) - 140;

		const dataNodes = nodes.value.map((n, i) => {
			if (n.id === "c") {
				return { ...n, x: cx, y: cy, fixed: true };
			}
			// 均匀环形分布
			const idx = i - 1;
			const angle = (idx / (nodes.value.length - 1)) * Math.PI * 2;
			const rLocal = radius + (n.r || 0);
			const x = cx + rLocal * Math.cos(angle);
			const y = cy + rLocal * Math.sin(angle);
			return { ...n, x, y };
		});

		chart.setOption({
			tooltip: {},
			series: [
				{
					type: "graph",
					layout: activeIndex.value === "圆形布局" ? "none" : "force",
					circular: { rotateLabel: true },
					force: { repulsion: 800, edgeLength: [80, 160] },
					roam: true,
					data: activeIndex.value === "圆形布局" ? dataNodes : nodes.value,
					links: links.value,
					edgeSymbol: ["none", "arrow"],
					edgeSymbolSize: [4, 10],
					lineStyle: { color: "rgba(174,214,255,1)", width: 2, opacity: 0.8 },
					edgeLabel: {
						show: true,
						position: "middle",
						distance: -18,
						formatter: ({ data }) => data?.label?.formatter || "",
						color: "rgb(5, 95, 194)",
						fontSize: 12,
						fontWeight: 400,
						fontFamily: "Microsoft YaHei",
						lineHeight: 24,
						backgroundColor: "rgba(231, 243, 255, 1)",
						borderRadius: 24,
						padding: [0, 12]
					},
					label: { show: true, position: "bottom", color: "rgb(59,65,75)", fontSize: 16 },
					itemStyle: { color: "rgba(5,95,194,1)" },
					emphasis: { focus: "adjacency" }
				}
			]
		});
	};
	setOption();
	const onResize = () => chart && chart.resize();
	window.addEventListener("resize", onResize);
	watch(activeIndex, () => setOption());
	onBeforeUnmount(() => {
		window.removeEventListener("resize", onResize);
		chart && chart.dispose();
	});
});
</script>

<style lang="scss" scoped>
* {
	padding: 0;
	margin: 0;
}
.character-relationships {
	width: 1600px;
	height: 688px;
	background-color: #fff;
	margin: 0 auto;
	position: relative;
	border-radius: 4px;
	box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
	.headerBox {
		position: absolute;
		top: 14px;
		left: 12px;
		display: flex;
		gap: 8px;
		.headerItem {
			display: flex;
			align-items: center;
			justify-content: center;
			width: 36px;
			height: 36px;
			border-radius: 4px;
			cursor: pointer;
			border: 1px solid rgb(230, 231, 232);
			background-color: #fff;
			transition: all 0.3s ease;
			img {
				width: 20px;
				height: 20px;
			}
		}
		.active {
			background-color: rgba(246, 250, 255, 1);
			border-color: rgb(5, 95, 194);
		}
	}
	.headerBtnBox {
		position: absolute;
		top: 14px;
		right: 12px;
		display: flex;
		gap: 4px;
		.btn-icon {
			width: 28px;
			height: 28px;
			cursor: pointer;
			transition: all 0.3s ease;
			&:hover {
				transform: scale(1.1);
			}
		}
	}
	.mainBox {
		width: 100%;
		height: 100%;
		padding-top: 42px;
		.graph {
			width: 100%;
			height: 100%;
		}
	}
}
</style>
