"use client";

import {
	type CSSProperties,
	type PointerEvent,
	useMemo,
	useRef,
	useState,
} from "react";

type ToolPosition = {
	id: string;
	name: string;
	x: number;
	y: number;
	z: number;
	type: string;
	color: string;
	summary: string;
	fit: string;
	limit: string;
};

type Point3D = {
	x: number;
	y: number;
	z: number;
};

type ProjectionMode = "xy" | "xz" | "yz" | "free";

const tools: ToolPosition[] = [
	{
		id: "manual",
		name: "纯人工",
		x: 24,
		y: 82,
		z: 22,
		type: "人主导",
		color: "#64748b",
		summary: "最懂业务，但查、写、跑、改、整理都靠人推进。",
		fit: "复杂边界判断、探索性分析、最终质量把关。",
		limit: "执行成本高，流程复用依赖个人习惯和文档质量。",
	},
	{
		id: "web-ai",
		name: "网页版 AI",
		x: 54,
		y: 24,
		z: 18,
		type: "通用 AI",
		color: "#38bdf8",
		summary: "适合问答、总结、生成草稿，启动快。",
		fit: "通用解释、文本生成、局部判断辅助。",
		limit: "不天然接入内部日志、标签规则、标准产物和团队流程。",
	},
	{
		id: "copilot",
		name: "IDE Copilot",
		x: 62,
		y: 34,
		z: 28,
		type: "编码辅助",
		color: "#60a5fa",
		summary: "在编辑器里提升局部编码效率。",
		fit: "补全、局部函数、单文件修改。",
		limit: "更偏代码片段，不负责跨系统数据流和业务产物链。",
	},
	{
		id: "cursor",
		name: "Cursor",
		x: 76,
		y: 46,
		z: 38,
		type: "IDE Agent",
		color: "#818cf8",
		summary: "围绕代码仓库做理解、修改和多文件协作。",
		fit: "工程代码迭代、仓库内上下文开发。",
		limit: "团队业务流程、线上数据、标准导出和共享 Skill 需要另行组织。",
	},
	{
		id: "code-agent",
		name: "Claude Code / Codex",
		x: 84,
		y: 58,
		z: 45,
		type: "工程 Agent",
		color: "#a78bfa",
		summary: "能读代码、调工具、执行多步工程任务。",
		fit: "本地工程闭环、复杂代码修改、命令执行。",
		limit: "强在个人工作区；团队级业务流程沉淀和 Web 多用户协作不是默认形态。",
	},
	{
		id: "notebook",
		name: "个人自动化脚本",
		x: 66,
		y: 74,
		z: 48,
		type: "个人自动化",
		color: "#f59e0b",
		summary: "贴近业务数据，能把部分流程脚本化。",
		fit: "数据清洗、临时统计、可重复实验。",
		limit: "入口、权限、review、产物管理和团队复用通常需要人额外维护。",
	},
	{
		id: "prompt-doc",
		name: "经验文档",
		x: 38,
		y: 62,
		z: 60,
		type: "经验沉淀",
		color: "#10b981",
		summary: "能记录规则和经验，便于传播。",
		fit: "标签边界、流程说明、操作规范。",
		limit: "本身不执行任务，仍需要人把文档转成操作。",
	},
	{
		id: "zk",
		name: "ZK Data Agent",
		x: 80,
		y: 88,
		z: 86,
		type: "业务 Agent 工作台",
		color: "#2563eb",
		summary:
			"把 Agent Loop、工具执行、业务知识、review 和产物管理组织成团队流程。",
		fit: "数据生成、线上挖掘、标签判断、外部系统 Skill 接入。",
		limit: "不替代人的业务判断；重点是把判断节点放进可复用流程。",
	},
];

const presets: Array<{
	mode: ProjectionMode;
	name: string;
	rotateX: number;
	rotateY: number;
}> = [
	{ mode: "xy", name: "研发 × 业务", rotateX: 0, rotateY: 0 },
	{ mode: "xz", name: "研发 × 复用", rotateX: -90, rotateY: 0 },
	{ mode: "yz", name: "业务 × 复用", rotateX: 0, rotateY: -90 },
];

const dimensionCards = [
	{
		title: "研发执行效率",
		text: "读代码、调工具、跑脚本、生成产物。",
	},
	{
		title: "业务嵌入深度",
		text: "接住日志、标签体系、数据格式和团队规则。",
	},
	{
		title: "流程可复用度",
		text: "把一次解决方案沉淀成团队能继续调用的能力。",
	},
];

const frictionCases = [
	{ text: "标签边界依赖经验", weight: 5 },
	{ text: "格式手工补齐", weight: 4 },
	{ text: "规则散在文档", weight: 4 },
	{ text: "线上数据难取", weight: 4 },
	{ text: "经验靠口口相传", weight: 3 },
	{ text: "脚本只在个人机器", weight: 3 },
	{ text: "Review 断在中间", weight: 3 },
	{ text: "样例难复用", weight: 2 },
	{ text: "产物路径分散", weight: 2 },
	{ text: "路径和权限反复确认", weight: 2 },
];

const cubeSize = 360;
const cubeCenter = cubeSize / 2;
const stageCenter = 280;
const perspective = 950;
const axisOrigin = { x: -cubeCenter, y: cubeCenter, z: -cubeCenter };
const axisDefinitions = [
	{
		id: "x",
		name: "研发执行效率",
		color: "#2563eb",
		start: axisOrigin,
		end: { x: cubeCenter, y: cubeCenter, z: -cubeCenter },
	},
	{
		id: "y",
		name: "业务嵌入深度",
		color: "#0f766e",
		start: axisOrigin,
		end: { x: -cubeCenter, y: -cubeCenter, z: -cubeCenter },
	},
	{
		id: "z",
		name: "流程可复用度",
		color: "#9333ea",
		start: axisOrigin,
		end: { x: -cubeCenter, y: cubeCenter, z: cubeCenter },
	},
];
const visibleAxesByMode: Record<ProjectionMode, string[]> = {
	xy: ["x", "y"],
	xz: ["x", "z"],
	yz: ["z", "y"],
	free: ["x", "y", "z"],
};

function score(tool: ToolPosition) {
	return Math.round((tool.x + tool.y + tool.z) / 3);
}

function clamp(value: number, min: number, max: number) {
	return Math.min(max, Math.max(min, value));
}

function getPointCoordinates(tool: ToolPosition) {
	return {
		x: (tool.x / 100) * cubeSize - cubeCenter,
		y: cubeCenter - (tool.y / 100) * cubeSize,
		z: (tool.z / 100) * cubeSize - cubeCenter,
	};
}

function projectPoint(
	point: Point3D,
	rotateX: number,
	rotateY: number,
	mode: ProjectionMode,
) {
	if (mode === "xy") {
		return {
			x: stageCenter + point.x,
			y: stageCenter + point.y,
			z: point.z,
			scale: 1,
		};
	}
	if (mode === "xz") {
		return {
			x: stageCenter + point.x,
			y: stageCenter - point.z,
			z: -point.y,
			scale: 1,
		};
	}
	if (mode === "yz") {
		return {
			x: stageCenter + point.z,
			y: stageCenter + point.y,
			z: point.x,
			scale: 1,
		};
	}

	const angleX = (rotateX * Math.PI) / 180;
	const angleY = (rotateY * Math.PI) / 180;
	const cosX = Math.cos(angleX);
	const sinX = Math.sin(angleX);
	const cosY = Math.cos(angleY);
	const sinY = Math.sin(angleY);
	const afterY = {
		x: point.x * cosY + point.z * sinY,
		y: point.y,
		z: -point.x * sinY + point.z * cosY,
	};
	const rotated = {
		x: afterY.x,
		y: afterY.y * cosX - afterY.z * sinX,
		z: afterY.y * sinX + afterY.z * cosX,
	};
	const scale = perspective / (perspective - rotated.z);

	return {
		x: stageCenter + rotated.x * scale,
		y: stageCenter + rotated.y * scale,
		z: rotated.z,
		scale,
	};
}

function toolAnchorStyle(
	tool: ToolPosition,
	projected: ReturnType<typeof projectPoint>,
) {
	const scale = Math.min(1.08, Math.max(0.88, projected.scale));

	return {
		"--tool-x": `${projected.x}px`,
		"--tool-y": `${projected.y}px`,
		"--label-scale": `${scale}`,
		"--point-color": tool.color,
		zIndex: Math.round(500 + projected.z),
	} as CSSProperties;
}

function getProjectedAxes(
	rotateX: number,
	rotateY: number,
	mode: ProjectionMode,
) {
	const visibleAxes = new Set(visibleAxesByMode[mode]);
	return axisDefinitions
		.filter((axis) => visibleAxes.has(axis.id))
		.map((axis) => {
			const start = projectPoint(axis.start, rotateX, rotateY, mode);
			const end = projectPoint(axis.end, rotateX, rotateY, mode);
			const vectorX = end.x - start.x;
			const vectorY = end.y - start.y;
			const length = Math.max(1, Math.hypot(vectorX, vectorY));
			const labelX = clamp(end.x + (vectorX / length) * 34, 44, 516);
			const labelY = clamp(end.y + (vectorY / length) * 34, 32, 528);

			return {
				...axis,
				start,
				end,
				labelStyle: {
					"--axis-label-x": `${labelX}px`,
					"--axis-label-y": `${labelY}px`,
					"--axis-color": axis.color,
				} as CSSProperties,
			};
		});
}

export function ToolPositionMap() {
	const [projectionMode, setProjectionMode] = useState<ProjectionMode>("xy");
	const [rotateX, setRotateX] = useState(0);
	const [rotateY, setRotateY] = useState(0);
	const [selectedId, setSelectedId] = useState("zk");
	const [hoveredId, setHoveredId] = useState<string | null>(null);
	const [isDragging, setIsDragging] = useState(false);
	const dragRef = useRef<{
		x: number;
		y: number;
		rotateX: number;
		rotateY: number;
	} | null>(null);

	const selected = useMemo(
		() => tools.find((tool) => tool.id === selectedId) ?? tools[0],
		[selectedId],
	);
	const projectedTools = useMemo(
		() =>
			tools
				.map((tool) => ({
					tool,
					projected: projectPoint(
						getPointCoordinates(tool),
						rotateX,
						rotateY,
						projectionMode,
					),
				}))
				.sort((a, b) => a.projected.z - b.projected.z),
		[rotateX, rotateY, projectionMode],
	);
	const projectedAxes = useMemo(
		() => getProjectedAxes(rotateX, rotateY, projectionMode),
		[rotateX, rotateY, projectionMode],
	);

	const handlePointerDown = (event: PointerEvent<HTMLDivElement>) => {
		setProjectionMode("free");
		dragRef.current = {
			x: event.clientX,
			y: event.clientY,
			rotateX,
			rotateY,
		};
		setIsDragging(true);
		event.currentTarget.setPointerCapture(event.pointerId);
	};

	const handlePointerMove = (event: PointerEvent<HTMLDivElement>) => {
		if (!dragRef.current) return;
		const deltaX = event.clientX - dragRef.current.x;
		const deltaY = event.clientY - dragRef.current.y;
		setRotateX(dragRef.current.rotateX - deltaY * 0.45);
		setRotateY(dragRef.current.rotateY + deltaX * 0.45);
	};

	const handlePointerEnd = (event: PointerEvent<HTMLDivElement>) => {
		dragRef.current = null;
		setIsDragging(false);
		if (event.currentTarget.hasPointerCapture(event.pointerId)) {
			event.currentTarget.releasePointerCapture(event.pointerId);
		}
	};

	return (
		<section className="project-doc-section project-doc-position" id="position">
			<div className="position-framing">
				<div className="position-framing-copy">
					<span>效率公式</span>
					<h3 className="position-formula">
						<span>团队效率</span>
						<b>≈</b>
						<span>研发执行效率</span>
						<b>×</b>
						<span>业务嵌入深度</span>
						<b>×</b>
						<span>流程可复用度</span>
					</h3>
					<p>
						AI
						能回答，脚本能处理，文档能沉淀。但只要其中一环还要人工来回衔接，效率就会被拉回到原来的流程里。
					</p>
				</div>
				<div className="position-dimension-grid">
					{dimensionCards.map((card) => (
						<div key={card.title}>
							<strong>{card.title}</strong>
							<p>{card.text}</p>
						</div>
					))}
				</div>
				<div className="position-friction-cloud">
					<strong>典型断点</strong>
					{frictionCases.map((item) => (
						<span className={`is-weight-${item.weight}`} key={item.text}>
							{item.text}
						</span>
					))}
					<em>下面这张图，就是把这些工作方式放进同一套坐标里看。</em>
				</div>
			</div>

			<div className="position-map-layout">
				<div className="position-stage-card">
					<div className="position-controls">
						<div>
							<span>
								{projectionMode === "free"
									? "拖动坐标系自由旋转"
									: "二维投影视图"}
							</span>
							<strong>
								{projectionMode === "free"
									? `X ${Math.round(rotateX)} / Y ${Math.round(rotateY)}`
									: presets.find((preset) => preset.mode === projectionMode)
											?.name}
							</strong>
						</div>
						<div className="position-preset-row">
							{presets.map((preset) => (
								<button
									className={
										projectionMode === preset.mode ? "is-selected" : undefined
									}
									key={preset.name}
									onClick={() => {
										setProjectionMode(preset.mode);
										setRotateX(preset.rotateX);
										setRotateY(preset.rotateY);
									}}
									type="button"
								>
									{preset.name}
								</button>
							))}
						</div>
					</div>

					<div
						className={
							isDragging ? "position-stage is-dragging" : "position-stage"
						}
						onPointerCancel={handlePointerEnd}
						onPointerDown={handlePointerDown}
						onPointerMove={handlePointerMove}
						onPointerUp={handlePointerEnd}
					>
						<div className="position-scene">
							<div className="position-space-grid" />
							<svg
								aria-hidden="true"
								className="position-axis-overlay"
								viewBox="0 0 560 560"
							>
								{projectedAxes.map((axis) => (
									<line
										key={axis.id}
										stroke={axis.color}
										x1={axis.start.x}
										x2={axis.end.x}
										y1={axis.start.y}
										y2={axis.end.y}
									/>
								))}
							</svg>
							<div className="position-axis-label-layer">
								{projectedAxes.map((axis) => (
									<span
										className="position-axis-label"
										key={axis.id}
										style={axis.labelStyle}
									>
										{axis.name}
									</span>
								))}
							</div>
							<div className="position-tool-layer">
								{projectedTools.map(({ tool, projected }) => (
									<button
										className={[
											"position-tool-anchor",
											tool.id === selectedId ? "is-selected" : "",
											tool.id === hoveredId ? "is-hovered" : "",
										]
											.filter(Boolean)
											.join(" ")}
										key={tool.id}
										onClick={() => setSelectedId(tool.id)}
										onBlur={() => setHoveredId(null)}
										onFocus={() => setHoveredId(tool.id)}
										onMouseEnter={() => setHoveredId(tool.id)}
										onMouseLeave={() => setHoveredId(null)}
										onPointerDown={(event) => event.stopPropagation()}
										style={toolAnchorStyle(tool, projected)}
										type="button"
									>
										<span className="position-ball" />
										<span className="position-tool-label">{tool.name}</span>
									</button>
								))}
							</div>
						</div>
					</div>
				</div>

				<aside className="position-detail-card">
					<div className="position-score">
						<span>{selected.type}</span>
						<strong>{score(selected)}</strong>
					</div>
					<h3>{selected.name}</h3>
					<p>{selected.summary}</p>
					<div className="position-meter-list">
						<div>
							<span>研发执行效率</span>
							<i style={{ width: `${selected.x}%` }} />
						</div>
						<div>
							<span>业务嵌入深度</span>
							<i style={{ width: `${selected.y}%` }} />
						</div>
						<div>
							<span>流程可复用度</span>
							<i style={{ width: `${selected.z}%` }} />
						</div>
					</div>
					<dl>
						<div>
							<dt>适合</dt>
							<dd>{selected.fit}</dd>
						</div>
						<div>
							<dt>限制</dt>
							<dd>{selected.limit}</dd>
						</div>
					</dl>
				</aside>
			</div>
		</section>
	);
}
