<template>
	<div class="tree-visualization">
		<div v-if="!hasData" class="no-data">
			<p>No data loaded. Please upload files to begin.</p>
			<p class="note">Note: Only root-level statistics available from saved data</p>
		</div>

		<div v-else class="tree-content">
			<svg
				:width="svgWidth"
				:height="svgHeight"
				:viewBox="`0 0 ${svgWidth} ${svgHeight}`"
				preserveAspectRatio="xMidYMid meet"
				class="tree-svg"
				ref="svgRef"
			>
				<g :transform="`translate(${centerX}, ${rootY})`">
					<!-- Root node -->
					<g class="root-node">
						<circle
							:r="rootRadius"
							fill="#4a90e2"
							stroke="#357abd"
							stroke-width="2"
							class="node-circle"
						/>
						<text y="5" text-anchor="middle" class="node-label">Root</text>
						<text y="20" text-anchor="middle" class="node-value">
							{{ totalVisits }} visits
						</text>
					</g>

					<!-- Links to children -->
					<g class="links">
						<path
							v-for="(child, idx) in visibleChildren"
							:key="child.actionKey"
							:d="getLinkPath(idx)"
							:stroke="getChildColor(child)"
							:stroke-width="getStrokeWidth(child)"
							fill="none"
							opacity="0.6"
							class="tree-link"
						/>
					</g>

					<!-- Child nodes -->
					<g class="child-nodes">
						<g
							v-for="(child, idx) in visibleChildren"
							:key="child.actionKey"
							:transform="getChildTransform(idx)"
							@mouseenter="onChildHover(child)"
							@mouseleave="onChildLeave"
							@click="onChildClick(child)"
							class="child-node"
							:class="{ selected: isSelected(child.actionKey) }"
						>
							<circle
								:r="getChildRadius(child)"
								:fill="getChildColor(child)"
								:stroke="isSelected(child.actionKey) ? '#e94560' : '#2a2a2a'"
								:stroke-width="isSelected(child.actionKey) ? 3 : 1"
								class="node-circle"
							/>
							<text y="-15" text-anchor="middle" class="node-label">
								{{ formatPosition(child.position) }}
							</text>
							<text y="0" text-anchor="middle" class="node-value">
								{{ child.N }}
							</text>
							<text y="12" text-anchor="middle" class="node-percent">
								{{ (child.pi * 100).toFixed(1) }}%
							</text>
						</g>
					</g>
				</g>
			</svg>

			<!-- Settings -->
			<div class="tree-settings">
				<label class="setting-label">
					Show top:
					<input
						type="range"
						min="5"
						max="20"
						:value="topN"
						@input="onTopNChange"
						class="setting-slider"
					/>
					<span class="setting-value">{{ topN }} moves</span>
				</label>
			</div>

			<!-- Tooltip -->
			<div
				v-if="hoveredChild"
				class="tooltip"
				:style="{ left: tooltipX + 'px', top: tooltipY + 'px' }"
			>
				<div class="tooltip-pos">{{ formatPosition(hoveredChild.position) }}</div>
				<div class="tooltip-line">Visit count: {{ hoveredChild.N }}</div>
				<div class="tooltip-line">
					Percentage: {{ ((hoveredChild.N / totalVisits) * 100).toFixed(1) }}%
				</div>
				<div class="tooltip-line">Policy π: {{ hoveredChild.pi.toFixed(3) }}</div>
			</div>
		</div>
	</div>
</template>

<script setup lang="ts">
import { ref, computed } from "vue";
import { useMCTSStore } from "@/stores/mctsStore";
import type { MCTSMoveStatistic } from "@/types/mcts";
import { formatPosition } from "@/utils/mctsDataParser";
import { getColorForStatistic } from "@/utils/mctsColorScale";

const mctsStore = useMCTSStore();

// Layout constants
const rootRadius = 30;
const rootY = 50; // Root node Y position
const childY = 150; // Child nodes Y position
const padding = 20; // Padding around content

// Settings
const topN = ref(10);

// Computed
const hasData = computed(() => mctsStore.hasData);
const totalVisits = computed(() => mctsStore.totalVisits);
const currentStatistics = computed(() => mctsStore.currentStatistics);

const visibleChildren = computed(() => {
	return currentStatistics.value
		.filter((stat: MCTSMoveStatistic) => stat.position !== null) // Exclude pass for tree view
		.sort((a: MCTSMoveStatistic, b: MCTSMoveStatistic) => b.N - a.N)
		.slice(0, topN.value);
});

// Calculate max child radius for accurate bounds
const maxChildRadius = computed(() => {
	if (visibleChildren.value.length === 0) return 15;
	const maxN = Math.max(...visibleChildren.value.map((c: MCTSMoveStatistic) => c.N));
	const minRadius = 15;
	const maxRadius = 35;
	return maxRadius; // Use max possible radius for bounds calculation
});

// Calculate horizontal spread
const horizontalSpread = computed(() => {
	const count = visibleChildren.value.length;
	if (count === 0) return 100;
	return Math.min(count * 80, 800);
});

// Calculate SVG dimensions based on content
const svgWidth = computed(() => {
	const calculatedWidth = horizontalSpread.value + padding * 2 + maxChildRadius.value * 2;
	return Math.max(calculatedWidth, 300); // Minimum width of 300px
});

const svgHeight = computed(() => {
	// Root at rootY with rootRadius, children at childY with maxChildRadius
	const calculatedHeight = childY + maxChildRadius.value + padding * 2;
	return Math.max(calculatedHeight, 250); // Minimum height of 250px
});

const centerX = computed(() => svgWidth.value / 2);

// Hover state
const hoveredChild = ref<MCTSMoveStatistic | null>(null);
const tooltipX = ref(0);
const tooltipY = ref(0);

// Functions
function getChildTransform(index: number): string {
	const count = visibleChildren.value.length;
	const spread = horizontalSpread.value;
	const startX = -spread / 2;
	const x = startX + (spread / (count - 1 || 1)) * index;
	return `translate(${x}, ${childY})`;
}

function getLinkPath(index: number): string {
	const count = visibleChildren.value.length;
	const spread = horizontalSpread.value;
	const startX = -spread / 2;
	const x = startX + (spread / (count - 1 || 1)) * index;

	// Curved path from root to child
	return `M 0,${rootRadius} Q 0,${childY / 2} ${x},${childY - getChildRadius(visibleChildren.value[index])}`;
}

function getChildRadius(child: MCTSMoveStatistic): number {
	// Size based on visit count
	const maxN = Math.max(...visibleChildren.value.map((c: MCTSMoveStatistic) => c.N));
	const minRadius = 15;
	const maxRadius = 35;
	return minRadius + ((child.N / maxN) * (maxRadius - minRadius));
}

function getChildColor(child: MCTSMoveStatistic): string {
	const maxN = Math.max(...visibleChildren.value.map((c: MCTSMoveStatistic) => c.N));
	return getColorForStatistic(child.N, "N", 0, maxN, mctsStore.colorScale);
}

function getStrokeWidth(child: MCTSMoveStatistic): number {
	// Thicker lines for more visited nodes
	const maxN = Math.max(...visibleChildren.value.map((c: MCTSMoveStatistic) => c.N));
	return 1 + (child.N / maxN) * 4;
}

function isSelected(actionKey: string): boolean {
	return mctsStore.selectedActionKey === actionKey;
}

function onChildHover(child: MCTSMoveStatistic) {
	hoveredChild.value = child;
}

function onChildLeave() {
	hoveredChild.value = null;
}

function onChildClick(child: MCTSMoveStatistic) {
	mctsStore.selectAction(child.actionKey);
}

function onTopNChange(event: Event) {
	const target = event.target as HTMLInputElement;
	topN.value = parseInt(target.value, 10);
	mctsStore.setTopNFilter(topN.value);
}

// Track mouse for tooltip
function onMouseMove(event: MouseEvent) {
	tooltipX.value = event.clientX + 10;
	tooltipY.value = event.clientY + 10;
}

if (typeof window !== "undefined") {
	window.addEventListener("mousemove", onMouseMove);
}
</script>

<style scoped lang="scss">
.tree-visualization {
	width: 100%;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: flex-start;
}

.no-data {
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
	height: 100%;
	gap: 10px;

	p {
		color: #606060;
		font-size: 14px;
		margin: 0;
	}

	.note {
		font-size: 11px;
		color: #808080;
		font-style: italic;
	}
}

.tree-content {
	display: flex;
	flex-direction: column;
	gap: 15px;
	width: 100%;
	align-items: center;
	justify-content: flex-start;
}

.tree-svg {
	display: block;
	max-width: 100%;
	height: auto;
}

.node-circle {
	cursor: pointer;
	transition: all 0.2s;
}

.child-node {
	cursor: pointer;

	&:hover .node-circle {
		filter: brightness(1.2);
	}

	&.selected .node-circle {
		filter: brightness(1.3);
	}
}

.node-label {
	fill: #e0e0e0;
	font-size: 11px;
	font-weight: 600;
	pointer-events: none;
}

.node-value {
	fill: #e0e0e0;
	font-size: 10px;
	pointer-events: none;
}

.node-percent {
	fill: #a0a0a0;
	font-size: 9px;
	pointer-events: none;
}

.tree-link {
	pointer-events: none;
}

/* Tree Settings */
.tree-settings {
	padding: 10px 15px;
	background-color: #1a1a1a;
	border-radius: 4px;
	display: flex;
	justify-content: center;
}

.setting-label {
	display: flex;
	align-items: center;
	gap: 10px;
	font-size: 12px;
	color: #c0c0c0;
}

.setting-slider {
	width: 150px;
	height: 4px;
	border-radius: 2px;
	background-color: #3a3a3a;
	outline: none;
	-webkit-appearance: none;

	&::-webkit-slider-thumb {
		-webkit-appearance: none;
		width: 12px;
		height: 12px;
		border-radius: 50%;
		background-color: #4a90e2;
		cursor: pointer;
	}

	&::-moz-range-thumb {
		width: 12px;
		height: 12px;
		border-radius: 50%;
		background-color: #4a90e2;
		cursor: pointer;
		border: none;
	}
}

.setting-value {
	font-weight: 500;
	color: #e0e0e0;
}

/* Tooltip */
.tooltip {
	position: fixed;
	background-color: rgba(0, 0, 0, 0.9);
	border: 1px solid #4a90e2;
	border-radius: 4px;
	padding: 8px 12px;
	font-size: 11px;
	color: #e0e0e0;
	pointer-events: none;
	z-index: 1000;
	box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}

.tooltip-pos {
	font-weight: 600;
	color: #4a90e2;
	margin-bottom: 4px;
}

.tooltip-line {
	color: #c0c0c0;
	line-height: 1.4;
}
</style>
