<template>
	<div class="trigo-view">
		<div class="view-header">
			<!-- Single Game Mode: Current Player & Move Count -->
			<div v-if="gameMode === 'single'" class="view-status">
				<span
					class="turn-indicator"
					:class="{ black: currentPlayer === 'black', white: currentPlayer === 'white' }"
				>
					{{ currentPlayer === "black" ? "Black" : "White" }}'s Turn
				</span>
				<span class="move-count">Move: {{ moveCount }}</span>
			</div>

			<!-- VS AI Mode: Player Info & AI Status -->
			<div v-else-if="gameMode === 'vs-ai'" class="view-status ai-mode">
				<div class="player-info" :class="{ 'on-turn': currentPlayer === humanPlayerColor }">
					<span class="player-label">You:</span>
					<span
						class="stone-icon"
						:class="humanPlayerColor === 'black' ? 'black' : 'white'"
					></span>
				</div>
				<button class="btn-swap-colors" @click="swapColors">⇄ Swap</button>
				<div class="ai-status" :class="{ 'on-turn': currentPlayer === aiPlayerColor && !aiThinking }">
					<span class="ai-indicator">🤖 AI:</span>
					<span v-if="!aiReady" class="ai-level">Loading...</span>
					<span v-else-if="aiThinking" class="ai-level ai-thinking">Thinking...</span>
					<span v-else-if="aiError" class="ai-level ai-error">Error</span>
					<span
						v-else
						class="stone-icon"
						:class="aiPlayerColor === 'black' ? 'black' : 'white'"
					></span>
				</div>
				<span class="move-count">Move: {{ moveCount }}</span>
				<span v-if="lastMoveTime > 0" class="ai-time">({{ lastMoveTime.toFixed(0) }}ms)</span>
			</div>

			<!-- VS People Mode: Room & Players -->
			<div v-else-if="gameMode === 'vs-people'" class="view-status people-mode">
				<div class="room-info">
					<span class="room-label">Room:</span>
					<span class="room-code">{{ playerStore.roomId || "---" }}</span>
					<button
						v-if="playerStore.roomId"
						class="btn-copy-room"
						@click="copyRoomCode"
						title="Copy room code"
					>
						📋
					</button>
				</div>

				<div class="players-info">
					<div class="player-display" :class="{ 'on-turn': isLocalPlayerTurn }">
						<inline-nickname-editor
							:nickname="playerStore.nickname"
							:editable="true"
							:player-color="playerStore.playerColor"
							@update="updateLocalNickname"
						/>
					</div>

					<span class="vs-divider">vs</span>

					<div class="player-display" :class="{ 'on-turn': !isLocalPlayerTurn }">
						<inline-nickname-editor
							v-if="playerStore.opponentNickname"
							:nickname="playerStore.opponentNickname"
							:editable="false"
							:player-color="opponentPlayerColor"
						/>
						<span v-else class="waiting-text">Waiting...</span>
					</div>
				</div>

				<span class="connection-status" :class="connectionStatusClass">
					{{ connectionStatusIcon }} {{ connectionStatusText }}
				</span>
			</div>

			<!-- Library Mode: Game Info & Controls -->
			<div v-else-if="gameMode === 'library'" class="view-status library-mode">
				<div class="game-info">
					<span class="game-title">Game #12345</span>
					<span class="game-date">2025-01-18</span>
				</div>
				<div class="library-actions">
					<button class="btn-library btn-load" title="Load Game">📂 Load</button>
					<button class="btn-library btn-export" title="Export TGN">📤 Export</button>
				</div>
			</div>

			<!-- Header Controls (right side) -->
			<div class="header-controls" v-if="gameMode === 'single'">
				<select v-model="selectedBoardShape" class="board-shape-select">
					<option value="3x3x3">3×3×3</option>
					<option value="5x5x5">5×5×5</option>
					<option value="7x7x7">7×7×7</option>
					<option value="9x9x1">9×9×1 (2D)</option>
					<option value="9x9x9">9×9×9</option>
					<option value="5x5x1">5×5×1 (2D)</option>
					<option value="7x7x1">7×7×1 (2D)</option>
				</select>
				<button class="btn-reset" @click="newGame">
					{{ gameStarted ? "Reset" : "Start" }}
				</button>
			</div>

			<div class="header-controls" v-else-if="gameMode === 'vs-ai'">
				<select v-model="selectedBoardShape" class="board-shape-select">
					<option value="3x3x3">3×3×3</option>
					<option value="5x5x5">5×5×5</option>
					<option value="7x7x7">7×7×7</option>
					<option value="9x9x1">9×9×1 (2D)</option>
					<option value="9x9x9">9×9×9</option>
					<option value="5x5x1">5×5×1 (2D)</option>
					<option value="7x7x1">7×7×1 (2D)</option>
				</select>
				<button class="btn-reset" @click="newGame">
					{{ gameStarted ? "Reset" : "Start" }}
				</button>
			</div>

			<div class="header-controls" v-else-if="gameMode === 'vs-people'">
				<room-selector
					:current-room="playerStore.roomId"
					:rooms="roomList"
					:loading="isLoadingRooms"
					:disabled="gameStarted && playerStore.hasOpponent"
					@create="handleCreateRoom"
					@select="handleRoomSelect"
				/>

				<select
					v-model="preferredColor"
					class="color-preference-select"
					:disabled="gameStarted || connectionStatus === 'in-room'"
				>
					<option value="black">Play as Black</option>
					<option value="white">Play as White</option>
				</select>

				<select v-model="selectedBoardShape" class="board-shape-select">
					<option value="3x3x3">3×3×3</option>
					<option value="5x5x5">5×5×5</option>
					<option value="7x7x7">7×7×7</option>
					<option value="9x9x1">9×9×1 (2D)</option>
					<option value="9x9x9">9×9×9</option>
					<option value="5x5x1">5×5×1 (2D)</option>
					<option value="7x7x1">7×7×1 (2D)</option>
				</select>

				<button class="btn-reset" @click="resetMultiplayerGame">Reset</button>
			</div>
		</div>

		<div class="view-body">
			<!-- 3D Board Canvas Area (Left) -->
			<div class="board-container">
				<div class="viewport-wrapper">
					<canvas ref="viewportCanvas" class="viewport-canvas"></canvas>
					<div class="viewport-overlay" v-if="isLoading">
						<p class="loading-text">Loading 3D Board...</p>
					</div>
					<!-- Inspect Mode Tooltip -->
					<div class="inspect-tooltip" v-if="inspectInfo.visible">
						<div class="tooltip-content">
							<span class="tooltip-label"
								>{{ inspectInfo.groupSize }} stone{{
									inspectInfo.groupSize > 1 ? "s" : ""
								}}</span
							>
							<span class="tooltip-divider">|</span>
							<span class="tooltip-label"
								>Liberties: {{ inspectInfo.liberties }}</span
							>
						</div>
					</div>
				</div>
			</div>

			<!-- Game Controls & Info Panel (Right) -->
			<div class="controls-panel">
				<!-- Score Display (Captured/Territory) -->
				<div
					class="panel-section score-section"
					:class="{ 'show-territory': showTerritoryMode }"
				>
					<h3 class="section-title">
						{{ showTerritoryMode ? "Territory" : "Captured" }}
					</h3>
					<div class="score-display">
						<button class="score-button black" :disabled="!gameStarted">
							<span class="color-indicator black-stone"></span>
							<span class="score">{{
								showTerritoryMode ? blackScore : capturedStones.black
							}}</span>
						</button>
						<button class="score-button white" :disabled="!gameStarted">
							<span class="color-indicator white-stone"></span>
							<span class="score">{{
								showTerritoryMode ? whiteScore : capturedStones.white
							}}</span>
						</button>
					</div>
					<button
						class="compute-territory"
						@click="computeTerritory"
						:disabled="!gameStarted"
					>
						Compute Territory
					</button>
				</div>

				<!-- Move History -->
				<div class="panel-section routine-section">
					<h3 class="section-title">
						Move History
						<button
							class="btn-view-tgn"
							@click="showTGNModal = true"
							title="View TGN Notation"
						>
							TGN
						</button>
					</h3>
					<div class="routine-content" ref="moveHistoryContainer">
						<div class="move-list">
							<!-- START placeholder -->
							<div
								:class="{ active: currentMoveIndex === 0 }"
								@click="jumpToMove(0)"
								class="move-row start-row"
							>
								<span class="round-number"></span>
								<span class="move-label open-label">OPEN</span>
							</div>
							<!-- Move history items by round -->
							<div
								v-for="(round, roundIndex) in moveRounds"
								:key="roundIndex"
								class="move-row"
							>
								<span class="round-number">{{ roundIndex + 1 }}.</span>
								<div
									class="move-cell black-move"
									:class="{ active: round.blackIndex === currentMoveIndex }"
									@click="jumpToMove(round.blackIndex)"
								>
									<span class="stone-icon black"></span>
									<span class="move-coords" v-if="!round.black.isPass">{{
										formatMoveCoords(round.black)
									}}</span>
									<span class="move-label" v-else>pass</span>
								</div>
								<div
									v-if="round.white"
									class="move-cell white-move"
									:class="{ active: round.whiteIndex === currentMoveIndex }"
									@click="jumpToMove(round.whiteIndex)"
								>
									<span class="stone-icon white"></span>
									<span class="move-coords" v-if="!round.white.isPass">{{
										formatMoveCoords(round.white)
									}}</span>
									<span class="move-label" v-else>pass</span>
								</div>
								<div v-else class="move-cell empty"></div>
							</div>
						</div>
					</div>
				</div>

				<!-- Game Controls -->
				<div class="panel-section controls-section">
					<h3 class="section-title">Controls</h3>
					<div class="control-buttons">
						<div class="play-controls">
							<button class="btn btn-pass" @click="pass" :disabled="!gameStarted">
								Pass
							</button>
							<button class="btn btn-resign" @click="resign" :disabled="!gameStarted">
								Resign
							</button>
						</div>
						<div class="history-controls">
							<button
								class="btn btn-icon btn-prev"
								@click="previousMove"
								:disabled="currentMoveIndex <= 0"
								title="Previous Move"
							>
								◀
							</button>
							<button
								class="btn btn-icon btn-next"
								@click="nextMove"
								:disabled="currentMoveIndex >= moveHistory.length"
								title="Next Move"
							>
								▶
							</button>
						</div>
					</div>
				</div>
			</div>
		</div>

		<!-- TGN Modal -->
		<div class="tgn-modal" v-if="showTGNModal" @click.self="showTGNModal = false">
			<div class="tgn-modal-content">
				<div class="tgn-modal-header">
					<h3>Game Notation (TGN)</h3>
					<div class="tgn-status" :class="tgnValidationClass">
						{{ tgnValidationMessage }}
					</div>
					<button class="btn-close" @click="showTGNModal = false">×</button>
				</div>
				<div class="tgn-modal-body">
					<textarea
						v-model="editableTGNContent"
						:class="['tgn-textarea', tgnValidationClass]"
						@input="onTGNEdit"
						placeholder="Enter TGN game notation..."
					></textarea>
				</div>
				<div class="tgn-modal-footer">
					<button class="btn btn-apply" @click="applyTGN" :disabled="!tgnIsValid">
						Apply TGN
					</button>
					<button class="btn btn-copy" @click="copyTGN">Copy to Clipboard</button>
					<button class="btn btn-close-modal" @click="showTGNModal = false">Close</button>
				</div>
			</div>
		</div>
	</div>
</template>

<script setup lang="ts">
	import { ref, onMounted, onUnmounted, watch, computed, nextTick } from "vue";
	import { useRoute } from "vue-router";
	import { TrigoViewport } from "@/services/trigoViewport";
	import { useGameStore } from "@/stores/gameStore";
	import { usePlayerStore } from "@/stores/playerStore";
	import { useTrigoAgent } from "@/composables/useTrigoAgent";
	import { useSocket } from "@/composables/useSocket";
	import { useRoomHash } from "@/composables/useRoomHash";
	import InlineNicknameEditor from "@/components/InlineNicknameEditor.vue";
	import RoomSelector, { type RoomSummary } from "@/components/RoomSelector.vue";
	import { storeToRefs } from "pinia";
	import type { BoardShape } from "../../../inc/trigo";
	import { Stone, validateMove, StoneType, validateTGN } from "../../../inc/trigo";
	import { TrigoGameFrontend } from "@/utils/TrigoGameFrontend";
	import { encodeAb0yz } from "../../../inc/trigo/ab0yz";
	import { storage, StorageKey } from "@/utils/storage";

	// Get current route to determine game mode
	const route = useRoute();
	const gameMode = computed(() => (route.meta.mode as string) || "single");

	// Game store
	const gameStore = useGameStore();
	const {
		game,
		currentPlayer,
		moveHistory,
		currentMoveIndex,
		capturedStones,
		gameStatus,
		boardShape,
		moveCount,
		isGameActive,
		passCount
	} = storeToRefs(gameStore);

	// Player store (for multiplayer)
	const playerStore = usePlayerStore();

	// Socket.io (for multiplayer)
	const socketApi = useSocket();

	// Room hash management (for VS People mode)
	const { getRoomIdFromHash, updateHash, clearHash, isValidRoomId } = useRoomHash();
	const isJoiningRoom = ref(false);

	// Room list state (for VS People mode room selector)
	const roomList = ref<RoomSummary[]>([]);
	const isLoadingRooms = ref(false);

	// Helper functions for board shape parsing
	const parseBoardShape = (shapeStr: string): BoardShape => {
		const parts = shapeStr
			.split(/[^\d]+/)
			.filter(Boolean)
			.map(Number);
		return { x: parts[0] || 5, y: parts[1] || 5, z: parts[2] || 5 };
	};

	const printBoardShape = (shape: BoardShape): string => {
		return `${shape.x}*${shape.y}*${shape.z}`;
	};

	// Format move coordinates using TGN notation
	const formatMoveCoords = (move: { x: number; y: number; z: number }): string => {
		const shape = boardShape.value;
		return encodeAb0yz([move.x, move.y, move.z], [shape.x, shape.y, shape.z]);
	};

	// AI Agent (for VS AI mode)
	const aiAgent = useTrigoAgent();
	const { isReady: aiReady, isThinking: aiThinking, error: aiError, lastMoveTime } = aiAgent;

	// AI player color with session storage persistence
	const loadAIColor = (): "black" | "white" => {
		const stored = storage.getString(StorageKey.AI_PLAYER_COLOR);
		return stored === "black" || stored === "white" ? stored : "white";
	};

	const aiPlayerColor = ref<"black" | "white">(loadAIColor());
	const humanPlayerColor = computed(() => (aiPlayerColor.value === "white" ? "black" : "white"));

	// VS People color preference with storage persistence
	const loadPreferredColor = (): "black" | "white" => {
		const stored = storage.getString("vs-people-color-preference");
		return stored === "black" || stored === "white" ? stored : "black";
	};

	const preferredColor = ref<"black" | "white">(loadPreferredColor());

	// Watch for color preference changes and persist to storage
	watch(preferredColor, (newColor) => {
		storage.setString("vs-people-color-preference", newColor);
	});

	// Local state
	const hoveredPosition = ref<string | null>(null);
	const blackScore = ref(0);
	const whiteScore = ref(0);
	const isLoading = ref(true);
	const selectedBoardShape = ref<string>(printBoardShape(boardShape.value));
	const showTerritoryMode = ref(false);
	const showTGNModal = ref(false);
	const inspectInfo = ref({
		visible: false,
		groupSize: 0,
		liberties: 0
	});

	// TGN Editor state
	const editableTGNContent = ref<string>("");
	const tgnValidationState = ref<"idle" | "valid" | "invalid">("idle");
	const tgnValidationError = ref<string>("");
	let tgnValidationTimeout: ReturnType<typeof setTimeout> | null = null;

	// Canvas reference and viewport
	const viewportCanvas = ref<HTMLCanvasElement | null>(null);
	const moveHistoryContainer = ref<HTMLDivElement | null>(null);
	let viewport: TrigoViewport | null = null;
	let resizeObserver: ResizeObserver | null = null;

	// Computed properties
	const gameStarted = computed(() => isGameActive.value);

	// Group moves into rounds (pairs of black and white moves)
	const moveRounds = computed(() => {
		const rounds: Array<{
			black: any;
			white: any | null;
			blackIndex: number;
			whiteIndex: number | null;
		}> = [];

		for (let i = 0; i < moveHistory.value.length; i += 2) {
			const blackMove = moveHistory.value[i];
			const whiteMove = moveHistory.value[i + 1] || null;

			rounds.push({
				black: blackMove,
				white: whiteMove,
				blackIndex: i + 1, // Convert array index to "moves applied" count
				whiteIndex: whiteMove ? i + 2 : null // Convert array index to "moves applied" count
			});
		}

		return rounds;
	});

	// Check if selected board shape differs from current game board shape
	const isBoardShapeDirty = computed(() => {
		const selectedShape = parseBoardShape(selectedBoardShape.value);
		const currentShape = boardShape.value;
		return (
			selectedShape.x !== currentShape.x ||
			selectedShape.y !== currentShape.y ||
			selectedShape.z !== currentShape.z
		);
	});

	// Generate TGN content
	const tgnContent = computed(() => {
		return (
			gameStore.game?.toTGN({
				application: "Trigo Demo v1.0",
				date: new Date().toISOString().split("T")[0].replace(/-/g, ".")
			}) || ""
		);
	});

	// TGN validation computed properties
	const tgnIsValid = computed(() => tgnValidationState.value === "valid");

	const tgnValidationClass = computed(() => {
		if (tgnValidationState.value === "idle") return "idle";
		if (tgnValidationState.value === "valid") return "valid";
		return "invalid";
	});

	const tgnValidationMessage = computed(() => {
		if (tgnValidationState.value === "idle") return "Ready to validate";
		if (tgnValidationState.value === "valid") return "✓ Valid TGN";
		return `✗ ${tgnValidationError.value}`;
	});

	// Debounced TGN validation (synchronous)
	const onTGNEdit = () => {
		// Clear existing timeout
		if (tgnValidationTimeout) {
			clearTimeout(tgnValidationTimeout);
		}

		// Set validation state to idle while waiting for debounce
		tgnValidationState.value = "idle";

		// Set new debounce timeout (300ms)
		tgnValidationTimeout = setTimeout(() => {
			const result = validateTGN(editableTGNContent.value);

			if (result.valid) {
				tgnValidationState.value = "valid";
				tgnValidationError.value = "";
			} else {
				tgnValidationState.value = "invalid";
				tgnValidationError.value = result.error || "Invalid TGN format";
			}
		}, 300);
	};

	// Apply TGN and update game state (synchronous)
	const applyTGN = () => {
		if (!tgnIsValid.value) return;

		try {
			const newGame = TrigoGameFrontend.fromTGN(editableTGNContent.value);

			// Update game store with the new TrigoGameFrontend instance
			gameStore.game = newGame;

			// Save to session storage
			gameStore.saveToSessionStorage();

			// Update viewport with new board state
			// The getters will automatically compute the new values from gameStore.game
			if (viewport) {
				viewport.setBoardShape(newGame.getShape());
				syncViewportWithStore();
			}

			// Close modal
			showTGNModal.value = false;
		} catch (err) {
			console.error("Failed to apply TGN:", err);
			tgnValidationState.value = "invalid";
			tgnValidationError.value = err instanceof Error ? err.message : "Failed to apply TGN";
		}
	};


	// Generate and apply AI move
	const generateAIMove = async () => {
		if (!aiReady.value || aiThinking.value || !gameStarted.value) {
			return;
		}

		try {
			console.log("[TrigoView] Generating AI move...");

			// Get AI move - pass the game instance directly from store
			const aiMove = await aiAgent.generateMove(gameStore.game);

			// Apply AI move if valid
			if (aiMove) {
				// Check if AI chose to pass
				if (aiMove.isPass) {
					console.log("[TrigoView] AI chose to pass");
					const result = gameStore.pass();
					if (result.success) {
						console.log(`[TrigoView] AI pass applied successfully (${lastMoveTime.value.toFixed(0)}ms)`);
					} else {
						console.error("[TrigoView] Failed to apply AI pass");
					}
				} else {
					console.log(`[TrigoView] AI suggests move at (${aiMove.x}, ${aiMove.y}, ${aiMove.z})`);

					// Make move in store
					const result = gameStore.makeMove(aiMove.x, aiMove.y, aiMove.z);

					if (result.success && viewport) {
						// Add AI stone to viewport
						const stoneColor = gameStore.opponentPlayer;
						viewport.addStone(aiMove.x, aiMove.y, aiMove.z, stoneColor);

						// Remove captured stones
						if (result.capturedPositions && result.capturedPositions.length > 0) {
							result.capturedPositions.forEach((pos: any) => {
								viewport.removeStone(pos.x, pos.y, pos.z);
							});
							console.log(`[TrigoView] AI captured ${result.capturedPositions.length} stone(s)`);
						}

						console.log(`[TrigoView] AI move applied successfully (${lastMoveTime.value.toFixed(0)}ms)`);
					}
				}
			} else {
				console.log("[TrigoView] AI returned no move");
			}
		} catch (err) {
			console.error("[TrigoView] Failed to generate AI move:", err);
		}
	};


	// Sync viewport with current game state (for undo/redo/reset)
	const syncViewportWithGame = () => {
		if (!viewport) return;

		// Get all stones from game store and add to viewport
		const stones = gameStore.getAllStones();
		for (const stone of stones) {
			viewport.addStone(stone.x, stone.y, stone.z, stone.color);
		}

		console.log(`[TrigoView] Synced viewport with ${stones.length} stones`);
	};


	// Handle stone placement
	const handleStoneClick = async (x: number, y: number, z: number) => {
		if (!gameStarted.value) return;

		// VS People mode: validate turn and emit socket event
		if (gameMode.value === "vs-people") {
			// Check if it's the local player's turn
			if (!isLocalPlayerTurn.value) {
				console.log("[TrigoView] Not your turn, ignoring click");
				return;
			}

			// Emit move to server (server will validate and broadcast)
			console.log(`[TrigoView] Emitting makeMove: (${x}, ${y}, ${z})`);
			socketApi.makeMove(x, y, z);
			return;
		}

		// Single player and VS AI mode: make move locally
		const result = gameStore.makeMove(x, y, z);

		if (result.success && viewport) {
			// Add stone to viewport (store already switched player, so use opponent)
			const stoneColor = gameStore.opponentPlayer;
			viewport.addStone(x, y, z, stoneColor);

			// Remove captured stones from viewport
			if (result.capturedPositions && result.capturedPositions.length > 0) {
				result.capturedPositions.forEach((pos) => {
					viewport.removeStone(pos.x, pos.y, pos.z);
				});
				console.log(`Captured ${result.capturedPositions.length} stone(s)`);
			}

			// Hide domain visualization and switch back to captured display after move
			viewport.hideDomainCubes();
			showTerritoryMode.value = false;

			// VS AI mode: Generate AI move after player move if it's AI's turn
			if (gameMode.value === "vs-ai" && aiReady.value && currentPlayer.value === aiPlayerColor.value) {
				setTimeout(() => {
					generateAIMove();
				}, 100);
			}
		}
	};

	// Handle position hover
	const handlePositionHover = (x: number | null, y: number | null, z: number | null) => {
		if (x !== null && y !== null && z !== null) {
			hoveredPosition.value = `(${x}, ${y}, ${z})`;
		} else {
			hoveredPosition.value = null;
		}
	};

	// Check if a position is droppable (validates with game rules)
	const isPositionDroppable = (x: number, y: number, z: number): boolean => {
		const pos = { x, y, z };
		const playerColor = currentPlayer.value === "black" ? StoneType.BLACK : StoneType.WHITE;

		const validation = validateMove(
			pos,
			playerColor,
			gameStore.board,
			boardShape.value,
			gameStore.lastCapturedPositions
		);

		return validation.valid;
	};

	// Handle inspect mode callback
	const handleInspectGroup = (groupSize: number, liberties: number) => {
		if (groupSize > 0) {
			inspectInfo.value = {
				visible: true,
				groupSize,
				liberties
			};
		} else {
			inspectInfo.value = {
				visible: false,
				groupSize: 0,
				liberties: 0
			};
		}
	};


	// Swap AI player color
	const swapColors = () => {
		// Swap the color
		aiPlayerColor.value = aiPlayerColor.value === "white" ? "black" : "white";

		// Save to storage
		storage.setString(StorageKey.AI_PLAYER_COLOR, aiPlayerColor.value);

		console.log(`[TrigoView] AI color swapped to: ${aiPlayerColor.value}`);

		// If game is started and it's now AI's turn, trigger AI move immediately
		if (gameStarted.value && aiReady.value && currentPlayer.value === aiPlayerColor.value) {
			setTimeout(() => {
				generateAIMove();
			}, 100);
		}
	};


	// Game control methods
	const newGame = () => {
		// Parse selected board shape
		const shape = parseBoardShape(selectedBoardShape.value);

		// Initialize game in store
		gameStore.initializeGame(shape);
		gameStore.startGame();

		// Update viewport with new board shape
		if (viewport) {
			viewport.setBoardShape(shape);
			viewport.clearBoard();
			viewport.setGameActive(true);

			// Exit territory mode if active
			viewport.hideDomainCubes();
		}

		// Reset scores and territory mode
		blackScore.value = 0;
		whiteScore.value = 0;
		showTerritoryMode.value = false;

		console.log(`Starting new game with board shape ${shape.x}×${shape.y}×${shape.z}`);

		// VS AI mode: If AI plays black, generate first move
		if (gameMode.value === "vs-ai" && aiPlayerColor.value === "black" && aiReady.value) {
			setTimeout(() => {
				generateAIMove();
			}, 100);
		}
	};

	// Reset game for multiplayer (VS People mode)
	const resetMultiplayerGame = () => {
		if (!confirm("Reset the game? This will clear all moves.")) return;

		const shape = parseBoardShape(selectedBoardShape.value);
		const swapColors = playerStore.playerColor !== preferredColor.value;

		socketApi.socket.emit("resetGame", {
			boardShape: shape,
			swapColors: swapColors
		}, (response: any) => {
			if (response.success) {
				console.log("Multiplayer game reset successfully");
				// Local reset is handled by gameReset event listener
			} else {
				console.error("Reset failed:", response.error);
				alert(`Failed to reset game: ${response.error || "Unknown error"}`);
			}
		});
	};

	const pass = () => {
		// VS People mode: validate turn and emit socket event
		if (gameMode.value === "vs-people") {
			if (!isLocalPlayerTurn.value) {
				console.log("[TrigoView] Not your turn, cannot pass");
				return;
			}
			console.log("[TrigoView] Emitting pass");
			socketApi.pass();
			return;
		}

		// Single player and VS AI mode: pass locally
		const previousPlayer = currentPlayer.value;
		const success = gameStore.pass();

		if (success) {
			// Check if game ended due to double pass
			//if (gameStore.gameResult?.reason === "double-pass") {
			//	showGameResult();
			//} else {
			console.log(`${previousPlayer} passed (Pass count: ${gameStore.passCount})`);
			//}
		}
	};

	const resign = () => {
		// Confirm resignation
		const confirmed = confirm(
			`Are you sure ${currentPlayer.value} wants to resign?\n\nThis will end the game immediately.`
		);

		if (!confirmed) return;

		if (gameMode.value === "vs-people") {
			// Multiplayer: emit resign to server
			socketApi.resign();
		} else {
			// Single player: local resign
			const success = gameStore.resign();
			if (success) {
				showGameResult();
			}
		}
	};

	const showGameResult = () => {
		const result = gameStore.gameResult;
		if (!result) return;

		// Don't set game as inactive - allow continued analysis
		// if (viewport) {
		// 	viewport.setGameActive(false);
		// }

		let message = "";
		if (result.reason === "resignation") {
			message = `${result.winner === "black" ? "Black" : "White"} wins by resignation!\n\nGame continues for analysis.`;
		} else if (result.reason === "double-pass") {
			// Calculate final scores for double pass
			const territory = gameStore.computeTerritory();
			const blackTotal = territory.black + capturedStones.value.black;
			const whiteTotal = territory.white + capturedStones.value.white;

			blackScore.value = blackTotal;
			whiteScore.value = whiteTotal;

			if (blackTotal > whiteTotal) {
				message = `Black wins by ${blackTotal - whiteTotal} points!\n\nBlack: ${blackTotal} points\nWhite: ${whiteTotal} points\n\nGame continues for analysis.`;
			} else if (whiteTotal > blackTotal) {
				message = `White wins by ${whiteTotal - blackTotal} points!\n\nWhite: ${whiteTotal} points\nBlack: ${blackTotal} points\n\nGame continues for analysis.`;
			} else {
				message = `Game is a draw!\n\nBoth players: ${blackTotal} points\n\nGame continues for analysis.`;
			}
		}

		setTimeout(() => {
			alert(message);
		}, 100);
	};

	const computeTerritory = () => {
		if (!gameStarted.value) return;

		// Toggle territory mode
		if (showTerritoryMode.value) {
			// Exit territory mode
			if (viewport) {
				viewport.hideDomainCubes();
			}
			showTerritoryMode.value = false;
			// Reset scores to captured stones count
			blackScore.value = 0;
			whiteScore.value = 0;
			return;
		}

		// Enter territory mode - Use store's territory calculation
		const territory = gameStore.computeTerritory();
		blackScore.value = territory.black + capturedStones.value.black;
		whiteScore.value = territory.white + capturedStones.value.white;

		// Switch to territory display mode
		showTerritoryMode.value = true;

		// Convert territory arrays to Sets of position keys for viewport
		if (viewport) {
			const blackDomain = new Set<string>();
			const whiteDomain = new Set<string>();

			// Use the calculated territory positions from the territory result
			territory.blackTerritory.forEach((pos) => {
				const key = `${pos.x},${pos.y},${pos.z}`;
				blackDomain.add(key);
			});

			territory.whiteTerritory.forEach((pos) => {
				const key = `${pos.x},${pos.y},${pos.z}`;
				whiteDomain.add(key);
			});

			// Set domain data and show both domains
			viewport.setDomainData(blackDomain, whiteDomain);
			viewport.setBlackDomainVisible(true);
			viewport.setWhiteDomainVisible(true);
		}

		console.log("Territory computed:", territory);
	};

	const previousMove = () => {
		const success = gameStore.undoMove();

		if (success && viewport) {
			// Rebuild viewport from current board state
			syncViewportWithStore();
		}
	};

	const nextMove = () => {
		const success = gameStore.redoMove();

		if (success && viewport) {
			// Rebuild viewport from current board state
			syncViewportWithStore();
		}
	};

	const jumpToMove = (index: number) => {
		const success = gameStore.jumpToMove(index);

		if (success && viewport) {
			// Rebuild viewport from current board state
			syncViewportWithStore();

			// Exit territory mode when navigating move history
			viewport.hideDomainCubes();
			showTerritoryMode.value = false;
			// Reset scores to 0 when exiting territory mode
			blackScore.value = 0;
			whiteScore.value = 0;
		}
	};

	// Sync viewport with store's board state
	const syncViewportWithStore = () => {
		if (!viewport) return;

		// Clear viewport
		viewport.clearBoard();

		// Read the actual board state from the store (which has captures applied)
		const board = gameStore.board;
		const shape = boardShape.value;

		// Add all stones that exist on the board
		for (let x = 0; x < shape.x; x++) {
			for (let y = 0; y < shape.y; y++) {
				for (let z = 0; z < shape.z; z++) {
					const stone = board[x][y][z];
					if (stone === Stone.Black) {
						viewport.addStone(x, y, z, "black");
					} else if (stone === Stone.White) {
						viewport.addStone(x, y, z, "white");
					}
				}
			}
		}

		// Set the last placed stone highlight based on current move index
		// currentMoveIndex represents the number of moves applied (not array index)
		// So the last applied move is at array index (currentMoveIndex - 1)
		if (currentMoveIndex.value > 0 && currentMoveIndex.value <= moveHistory.value.length) {
			const lastMove = moveHistory.value[currentMoveIndex.value - 1];
			viewport.setLastPlacedStone(lastMove.x, lastMove.y, lastMove.z);
		} else {
			// No moves applied or at START position
			viewport.setLastPlacedStone(null, null, null);
		}
	};

	// ===== VS People Mode: Nickname Management =====

	// Computed properties for multiplayer
	const opponentPlayerColor = computed(() => {
		if (!playerStore.playerColor) return null;
		return playerStore.playerColor === "black" ? "white" : "black";
	});

	const isLocalPlayerTurn = computed(() => {
		return currentPlayer.value === playerStore.playerColor;
	});

	const connectionStatusClass = computed(() => {
		return playerStore.connectionStatus === "in-room" ? "connected" : "disconnected";
	});

	const connectionStatusText = computed(() => {
		if (playerStore.connectionStatus === "in-room") return "Connected";
		if (playerStore.connectionStatus === "connected") return "Joining room...";
		return "Disconnected";
	});

	const connectionStatusIcon = computed(() => {
		if (playerStore.connectionStatus === "in-room") return "🟢";
		if (playerStore.connectionStatus === "connected") return "🟡"; // Yellow while joining
		return "🔴";
	});

	// Update local player nickname
	const updateLocalNickname = (newNickname: string) => {
		const success = playerStore.setNickname(newNickname);

		if (!success) {
			console.error("Failed to update nickname");
			return;
		}

		// If in a room, broadcast nickname change to opponents
		if (playerStore.isInRoom) {
			socketApi.changeNickname(newNickname, (response: any) => {
				if (!response.success) {
					console.error("Failed to broadcast nickname change:", response.error);
					alert(`Failed to change nickname: ${response.error}`);
				}
			});
		}
	};

	// Copy room code to clipboard
	const copyRoomCode = () => {
		if (!playerStore.roomId) return;

		navigator.clipboard
			.writeText(playerStore.roomId)
			.then(() => alert("Room code copied to clipboard!"))
			.catch((err) => console.error("Failed to copy room code:", err));
	};


	// ===== Room Management Functions (VS People Mode) =====

	/**
	 * Wait for socket connection with timeout
	 * Prevents race condition where hash is read before socket connects
	 */
	async function waitForSocketConnection(timeout = 5000): Promise<void> {
		return new Promise((resolve, reject) => {
			if (socketApi.socket.connected) {
				resolve();
				return;
			}

			const checkInterval = setInterval(() => {
				if (socketApi.socket.connected) {
					clearInterval(checkInterval);
					clearTimeout(timeoutHandle);
					resolve();
				}
			}, 100);

			const timeoutHandle = setTimeout(() => {
				clearInterval(checkInterval);
				reject(new Error("Socket connection timeout"));
			}, timeout);
		});
	}


	/**
	 * Room list management for room selector dropdown
	 */
	function fetchRoomList() {
		console.log("[TrigoView] fetchRoomList() called, socket connected:", socketApi.socket.connected, "socket id:", socketApi.socket.id);
		isLoadingRooms.value = true;
		socketApi.listRooms((response: any) => {
			console.log("[TrigoView] listRooms response:", response);
			isLoadingRooms.value = false;
			if (response.success) {
				roomList.value = response.rooms || [];
				console.log("[TrigoView] Room list updated, count:", roomList.value.length, "rooms:", roomList.value.map((r: any) => r.id));
			} else {
				console.error("[TrigoView] listRooms failed:", response.error);
			}
		});
	}

	function setupRoomListeners() {
		console.log("[TrigoView] Setting up room listeners, socket connected:", socketApi.socket.connected, "socket id:", socketApi.socket.id);

		socketApi.onRoomCreated((data: RoomSummary) => {
			console.log("[TrigoView] >>> Received roomCreated event:", data);
			console.log("[TrigoView] Current roomList before add:", JSON.stringify(roomList.value));
			// Add new room to list if not already present
			if (!roomList.value.find(r => r.id === data.id)) {
				roomList.value = [...roomList.value, data]; // Use spread to ensure reactivity
				console.log("[TrigoView] Added room to list, new count:", roomList.value.length, "rooms:", roomList.value.map(r => r.id));
			}
		});

		socketApi.onRoomUpdated((data: RoomSummary) => {
			console.log("[TrigoView] >>> Received roomUpdated event:", data);
			const index = roomList.value.findIndex(r => r.id === data.id);
			if (index >= 0) {
				roomList.value = [...roomList.value.slice(0, index), data, ...roomList.value.slice(index + 1)];
			} else {
				roomList.value = [...roomList.value, data];
			}
			console.log("[TrigoView] roomList after update:", roomList.value.map(r => r.id));
		});

		socketApi.onRoomDeleted((data: { roomId: string }) => {
			console.log("[TrigoView] >>> Received roomDeleted event:", data);
			roomList.value = roomList.value.filter(r => r.id !== data.roomId);
			console.log("[TrigoView] roomList after delete:", roomList.value.map(r => r.id));
		});
	}

	function cleanupRoomListeners() {
		socketApi.offRoomCreated();
		socketApi.offRoomUpdated();
		socketApi.offRoomDeleted();
	}

	// Room selector event handlers
	async function handleRoomSelect(roomId: string) {
		if (playerStore.roomId === roomId) return; // Already in this room

		// Leave current room if any
		if (playerStore.roomId) {
			socketApi.leaveRoom();
			playerStore.leaveRoom();
		}

		// Join selected room
		await joinRoomByHash(roomId);
	}

	async function handleCreateRoom() {
		// Leave current room if any
		if (playerStore.roomId) {
			socketApi.leaveRoom();
			playerStore.leaveRoom();
		}

		clearHash();
		await createAndJoinRoom();
	}


	/**
	 * Initialize multiplayer room based on URL hash
	 * - No hash: create new room
	 * - Valid hash: join existing room
	 * - Invalid hash: redirect to create new room
	 */
	async function initializeMultiplayerRoom() {
		console.log("[TrigoView] ========== INITIALIZE MULTIPLAYER ROOM ==========");
		console.log("[TrigoView] isJoiningRoom:", isJoiningRoom.value);
		console.log("[TrigoView] Socket connected:", socketApi.socket.connected);
		console.log("[TrigoView] Socket ID:", socketApi.socket.id);

		if (isJoiningRoom.value) {
			console.log("[TrigoView] Already joining, skipping");
			return; // Prevent duplicate joins
		}

		const hashRoomId = getRoomIdFromHash();
		console.log("[TrigoView] hashRoomId from URL:", hashRoomId);

		if (!hashRoomId) {
			// No hash: create new room
			console.log("[TrigoView] No hash found, creating new room");
			await createAndJoinRoom();
		} else if (isValidRoomId(hashRoomId)) {
			// Valid hash: join existing room
			console.log("[TrigoView] Valid hash found, joining room:", hashRoomId);
			await joinRoomByHash(hashRoomId);
		} else {
			// Invalid hash: redirect to create new room
			console.warn(`[TrigoView] Invalid room ID in hash: ${hashRoomId}`);
			clearHash();
			await createAndJoinRoom();
		}
	}


	/**
	 * Create a new room and join it
	 */
	async function createAndJoinRoom() {
		console.log("[TrigoView] createAndJoinRoom called, isJoiningRoom:", isJoiningRoom.value);
		if (isJoiningRoom.value) {
			console.log("[TrigoView] Already joining, returning");
			return;
		}
		isJoiningRoom.value = true;
		console.log("[TrigoView] Set isJoiningRoom to true");

		try {
			console.log("[TrigoView] Waiting for socket connection...");
			await waitForSocketConnection();
			console.log("[TrigoView] Socket connection ready, calling joinRoom");

			socketApi.joinRoom({ nickname: playerStore.nickname }, (response: any) => {
				console.log("[TrigoView] joinRoom callback received:", response);
				isJoiningRoom.value = false;

				if (response.success !== false && response.roomId) {
					playerStore.joinRoom(response.roomId, response.playerColor);
					updateHash(response.roomId);
					console.log(`[TrigoView] Room created: ${response.roomId}`);
				} else {
					console.error("[TrigoView] Failed to create room:", response.error);
					alert("Failed to create room. Please try again.");
				}
			});
		} catch (err) {
			isJoiningRoom.value = false;
			console.error("[TrigoView] Socket connection failed:", err);
			alert("Connection failed. Please check your internet and try again.");
		}
	}


	/**
	 * Join an existing room by room ID from hash
	 */
	async function joinRoomByHash(roomId: string) {
		if (isJoiningRoom.value) return;
		isJoiningRoom.value = true;

		try {
			await waitForSocketConnection();

			socketApi.joinRoom({ roomId, nickname: playerStore.nickname }, (response: any) => {
				isJoiningRoom.value = false;

				if (response.success !== false && response.roomId) {
					playerStore.joinRoom(response.roomId, response.playerColor);
					console.log(`[TrigoView] Room joined: ${response.roomId}`);

					// Sync game state from server (board shape, moves, etc.)
					if (response.gameState) {
						const gs = response.gameState;
						console.log(`[TrigoView] Syncing game state:`, gs);

						// Get board shape from server
						const serverBoardShape = gs.boardShape || boardShape.value;

						// Try to load from TGN, fall back to initializeGame
						let loaded = false;
						if (gs.tgn) {
							loaded = gameStore.loadFromTGN(gs.tgn);
						}

						if (!loaded) {
							gameStore.initializeGame(serverBoardShape);
							if (gs.gameStatus === "playing") {
								gameStore.startGame();
							}
						}

						// Update viewport with server's board shape
						if (viewport) {
							viewport.setBoardShape(serverBoardShape);
							viewport.clearBoard();

							// Re-render all stones from game state
							const stones = gameStore.getAllStones();
							for (const stone of stones) {
								viewport.addStone(stone.x, stone.y, stone.z, stone.color);
							}

							if (gs.gameStatus === "playing") {
								viewport.setGameActive(true);
							}
						}

						// Update board shape dropdown
						selectedBoardShape.value = printBoardShape(serverBoardShape);
					}

					// Extract opponent from players list
					if (response.players && socketApi.socket.id) {
						for (const [playerId, player] of Object.entries(response.players) as [string, any][]) {
							if (playerId !== socketApi.socket.id) {
								playerStore.setOpponentNickname(player.nickname);
								console.log(`[TrigoView] Opponent found: ${player.nickname}`);
								break;
							}
						}
					}

					// Start game if both players are present
					const playerCount = response.players ? Object.keys(response.players).length : 0;
					if (playerCount >= 2 && !gameStarted.value) {
						gameStore.startGame();
						if (viewport) {
							viewport.setGameActive(true);
						}
						console.log("[TrigoView] Game started - both players present");
					}
				} else {
					console.warn(`[TrigoView] Failed to join room:`, response.error);
					handleJoinFailure(response.error || "Failed to join room");
				}
			});
		} catch (err) {
			isJoiningRoom.value = false;
			console.error("[TrigoView] Socket connection failed:", err);
			alert("Connection failed. Please check your internet and try again.");
		}
	}


	/**
	 * Handle room join failure
	 * Clears invalid hash and creates new room
	 */
	function handleJoinFailure(error: string) {
		clearHash();

		if (error.includes("not found")) {
			alert("Room not found. Creating a new room...");
		} else if (error.includes("full")) {
			alert("This room is full. Creating a new room...");
		} else {
			alert(`Failed to join room: ${error}. Creating a new room...`);
		}

		createAndJoinRoom();
	}


	/**
	 * Handle browser navigation (back/forward) and URL changes
	 * With hash routing, room IDs are in query params, so we listen for popstate
	 */
	function handleUrlChange() {
		if (gameMode.value !== "vs-people") return;

		const currentRoomParam = getRoomIdFromHash();
		const currentRoom = playerStore.roomId;

		if (currentRoomParam !== currentRoom) {
			if (currentRoomParam && isValidRoomId(currentRoomParam)) {
				// User navigated to different room
				if (currentRoom) socketApi.leaveRoom();
				joinRoomByHash(currentRoomParam);
			} else {
				// Invalid or removed room param
				if (currentRoom) {
					updateHash(currentRoom); // Restore correct room param
				} else {
					createAndJoinRoom(); // Create new room
				}
			}
		}
	}

	// ===== Watchers =====

	// Watch for current player changes to update viewport preview
	watch(currentPlayer, (newPlayer) => {
		if (viewport) {
			viewport.setCurrentPlayer(newPlayer);
		}
	});

	// Watch currentMoveIndex to auto-scroll move history to keep current move visible
	watch(currentMoveIndex, () => {
		// Use nextTick to ensure DOM is updated before scrolling
		nextTick(() => {
			if (moveHistoryContainer.value) {
				// Find the active move element
				const activeElement = moveHistoryContainer.value.querySelector(".active");
				if (activeElement) {
					// Scroll the active element into view smoothly
					activeElement.scrollIntoView({ behavior: "smooth", block: "nearest" });
				}
			}
		});
	});

	// Watch playerStore.roomId to sync URL hash (VS People mode)
	watch(
		() => playerStore.roomId,
		(newRoomId) => {
			if (gameMode.value !== "vs-people") return;

			if (newRoomId) {
				updateHash(newRoomId);
			} else {
				clearHash();
			}
		}
	);

	// Watch TGN modal to populate editable content when opened
	watch(showTGNModal, (isVisible) => {
		if (isVisible) {
			// Populate with current game's TGN when modal opens
			editableTGNContent.value = tgnContent.value;
			tgnValidationState.value = "valid"; // Current TGN is always valid
			tgnValidationError.value = "";
		}
	});


	// Flag to track if VS People mode has been initialized
	let vsPeopleModeInitialized = false;

	// Initialize VS People mode - sets up all socket event listeners
	const initializeVsPeopleMode = () => {
		if (vsPeopleModeInitialized) {
			console.log("[TrigoView] VS People mode already initialized, skipping...");
			return;
		}

		console.log("[TrigoView] Initializing VS People mode...");
		vsPeopleModeInitialized = true;

		// Listen for nickname changes
		socketApi.onNicknameChanged((data) => {
			console.log(
				`[TrigoView] Player ${data.playerId} changed nickname: ${data.oldNickname} -> ${data.nickname}`
			);

			// If it's not us, update opponent nickname
			if (data.playerId !== socketApi.socket.id) {
				playerStore.setOpponentNickname(data.nickname);
			}
		});

		// Listen for game updates (moves, passes, undo, redo)
		socketApi.onGameUpdate((data) => {
			console.log("[TrigoView] Game update received:", data);

			// Update current player from server
			if (data.currentPlayer) {
				gameStore.setCurrentPlayer(data.currentPlayer);
			}

			// Handle different actions
			if (data.action === "move" && data.lastMove) {
				const { x, y, z } = data.lastMove;
				// Apply move to local game state
				const result = gameStore.makeMove(x, y, z);

				if (result.success && viewport) {
					// Add stone to viewport
					const stoneColor = gameStore.opponentPlayer;
					viewport.addStone(x, y, z, stoneColor);

					// Remove captured stones
					if (data.capturedPositions && data.capturedPositions.length > 0) {
						data.capturedPositions.forEach((pos: { x: number; y: number; z: number }) => {
							viewport.removeStone(pos.x, pos.y, pos.z);
						});
						console.log(`[TrigoView] Captured ${data.capturedPositions.length} stone(s)`);
					}

					// Hide territory visualization
					viewport.hideDomainCubes();
					showTerritoryMode.value = false;
				}
			} else if (data.action === "pass") {
				gameStore.pass();
				console.log("[TrigoView] Pass received from server");
			} else if (data.action === "undo" || data.action === "redo") {
				// For undo/redo, reload game from TGN
				if (data.tgn && viewport) {
					gameStore.loadFromTGN(data.tgn);
					// Resync viewport with game state
					viewport.clearBoard();
					syncViewportWithGame();
				}
			}
		});

		// Listen for player joined
		socketApi.onPlayerJoined((data) => {
			console.log("[TrigoView] Player joined:", data);
			playerStore.setOpponentNickname(data.nickname);

			// Start game when second player joins
			if (!gameStarted.value) {
				gameStore.startGame();
				if (viewport) {
					viewport.setGameActive(true);
				}
				console.log("[TrigoView] Game started - opponent joined");
			}
		});

		// Listen for player left
		socketApi.onPlayerLeft((data) => {
			console.log("[TrigoView] Player left:", data);
			playerStore.setOpponentNickname(null);
		});

		// Listen for player disconnected
		socketApi.onPlayerDisconnected((data) => {
			console.log("[TrigoView] Player disconnected:", data);
			if (data.playerId !== socketApi.socket.id) {
				playerStore.setOpponentNickname(null);
			}
		});

		// Listen for game ended
		socketApi.onGameEnded((data) => {
			console.log("[TrigoView] Game ended:", data);
			alert(`Game ended! Winner: ${data.winner || "None"}\nReason: ${data.reason}`);
		});

		// Listen for game reset
		socketApi.onGameReset((data) => {
			console.log("[TrigoView] Game reset:", data);

			// Get the new board shape from server, or use current
			const newBoardShape = data.boardShape || boardShape.value;

			// Reload game state - try TGN first, fall back to initializeGame
			let loaded = false;
			if (data.tgn) {
				loaded = gameStore.loadFromTGN(data.tgn);
			}

			// If TGN loading failed or no TGN, use initializeGame with new board shape
			if (!loaded) {
				gameStore.initializeGame(newBoardShape);
				gameStore.startGame();
			}

			// Update viewport with new board shape and clear
			if (viewport) {
				viewport.setBoardShape(newBoardShape);
				viewport.clearBoard();
				viewport.setGameActive(true);
			}

			// Update the board shape dropdown to match
			selectedBoardShape.value = printBoardShape(newBoardShape);

			// Update player colors if changed
			if (data.players && socketApi.socket.id) {
				const myPlayer = data.players[socketApi.socket.id];
				if (myPlayer) {
					playerStore.playerColor = myPlayer.color;
				}
			}
		});

		// Listen for errors
		socketApi.onError((data) => {
			console.error("[TrigoView] Socket error:", data.message);
		});

		// Setup room list listeners for room selector
		setupRoomListeners();

		// Set player ID when socket connects
		if (socketApi.socket.id) {
			playerStore.setPlayerId(socketApi.socket.id);
		}

		// Listen for browser navigation (back/forward) and URL changes
		window.addEventListener("popstate", handleUrlChange);

		// Handle socket connection and reconnection
		socketApi.socket.on("connect", () => {
			console.log("[TrigoView] Socket connected in VS People mode");

			// Update player ID and connection status
			if (socketApi.socket.id) {
				playerStore.setPlayerId(socketApi.socket.id);
			}

			// Fetch room list for room selector
			fetchRoomList();

			// Initialize room based on URL hash (only if not already in a room)
			if (!playerStore.roomId && !isJoiningRoom.value) {
				console.log("[TrigoView] Initializing room after socket connection");
				initializeMultiplayerRoom();
			}
		});

		// Handle socket disconnection
		socketApi.socket.on("disconnect", () => {
			console.log("[TrigoView] Socket disconnected in VS People mode");
			// Don't reset roomId - we want to rejoin on reconnect
			if (playerStore.roomId) {
				playerStore.connectionStatus = "connected"; // Still have room info, just disconnected
			} else {
				playerStore.disconnect();
			}
		});

		// If socket is already connected, initialize room immediately
		if (socketApi.socket.connected) {
			console.log("[TrigoView] Socket already connected, initializing room");
			fetchRoomList();
			initializeMultiplayerRoom();
		}
	};


	// Cleanup VS People mode - removes all socket event listeners
	const cleanupVsPeopleMode = () => {
		if (!vsPeopleModeInitialized) {
			return;
		}

		console.log("[TrigoView] Cleaning up VS People mode...");
		vsPeopleModeInitialized = false;

		socketApi.offNicknameChanged();
		socketApi.offGameUpdate();
		socketApi.offPlayerJoined();
		socketApi.offPlayerLeft();
		socketApi.offPlayerDisconnected();
		socketApi.offGameEnded();
		socketApi.offGameReset();
		socketApi.offError();
		cleanupRoomListeners();

		// Remove URL change listener
		window.removeEventListener("popstate", handleUrlChange);

		// Remove socket event listeners
		socketApi.socket.off("connect");
		socketApi.socket.off("disconnect");

		// Reset player store state
		playerStore.disconnect();
	};


	// Lifecycle hooks
	onMounted(() => {
		console.log("[TrigoView] Component mounted, gameMode:", gameMode.value, "route.path:", route.path, "route.meta.mode:", route.meta.mode);

		// In VS People mode, always start fresh (server maintains authoritative state)
		// In other modes, try to restore from session storage
		let restoredFromStorage = false;
		if (gameMode.value !== "vs-people") {
			restoredFromStorage = gameStore.loadFromSessionStorage();
		}

		// If not restored from storage, initialize new game
		if (!restoredFromStorage) {
			// Parse initial board shape
			const shape = parseBoardShape(selectedBoardShape.value);

			// Initialize game store
			gameStore.initializeGame(shape);
		} else {
			// Update selected board shape to match restored state
			selectedBoardShape.value = printBoardShape(boardShape.value);
			console.log("Restored game state from session storage");
		}

		// Initialize Three.js viewport with current board shape
		if (viewportCanvas.value) {
			viewport = new TrigoViewport(viewportCanvas.value, boardShape.value, {
				onStoneClick: handleStoneClick,
				onPositionHover: handlePositionHover,
				isPositionDroppable: isPositionDroppable,
				onInspectGroup: handleInspectGroup
			});
			console.log("TrigoViewport initialized");

			// Hide loading overlay after viewport is initialized
			isLoading.value = false;

			// If game was restored, sync viewport with restored board state
			if (restoredFromStorage) {
				syncViewportWithStore();
				viewport.setGameActive(isGameActive.value);
			}

			// Setup ResizeObserver to handle canvas resizing when sidebar expands/collapses
			resizeObserver = new ResizeObserver((entries) => {
				for (const entry of entries) {
					if (entry.target === viewportCanvas.value && viewport) {
						// Trigger viewport resize
						const rect = viewportCanvas.value.getBoundingClientRect();
						//console.log(`Canvas resized: ${rect.width}x${rect.height}`);

						// Call the viewport's resize handler directly
						// The onWindowResize method updates camera aspect and renderer size
						(viewport as any).onWindowResize();
					}
				}
			});

			// Observe the canvas element for size changes
			resizeObserver.observe(viewportCanvas.value);
			console.log("ResizeObserver attached to canvas");
		}

		// Start game automatically if not restored or was playing
		if (!restoredFromStorage || gameStore.gameStatus === "idle") {
			gameStore.startGame();
			if (viewport) {
				viewport.setGameActive(true);
			}
		}

		// Initialize AI agent in VS AI mode
		if (gameMode.value === "vs-ai") {
			console.log("[TrigoView] Initializing AI agent for VS AI mode...");
			aiAgent.initialize().catch((err) => {
				console.error("[TrigoView] Failed to initialize AI agent:", err);
			});
		}

		// Initialize VS People mode if needed
		if (gameMode.value === "vs-people") {
			initializeVsPeopleMode();
		}

		// Add keyboard shortcuts
		window.addEventListener("keydown", handleKeyPress);

		// Expose testing API to window for debugging/testing
		(window as any).trigoApi = {
			// Get current game state
			getState: () => ({
				gameMode: gameMode.value,
				roomId: playerStore.roomId,
				playerColor: playerStore.playerColor,
				connectionStatus: playerStore.connectionStatus,
				currentPlayer: currentPlayer.value,
				moveCount: moveHistory.value.length,
				boardShape: boardShape.value,
				isConnected: socketApi.socket.connected
			}),

			// Reset game without confirmation dialog (for VS People mode)
			resetGame: (boardShapeStr?: string) => {
				const shape = boardShapeStr
					? parseBoardShape(boardShapeStr)
					: parseBoardShape(selectedBoardShape.value);

				if (gameMode.value === "vs-people") {
					return new Promise((resolve) => {
						socketApi.socket.emit("resetGame", {
							boardShape: shape,
							swapColors: false
						}, (response: any) => {
							if (response.success) {
								console.log("[trigoApi] Game reset successfully");
								resolve({ success: true });
							} else {
								console.error("[trigoApi] Reset failed:", response.error);
								resolve({ success: false, error: response.error });
							}
						});
					});
				} else {
					// Single player mode
					gameStore.initializeGame(shape);
					gameStore.startGame();
					if (viewport) {
						viewport.setBoardShape(shape);
						viewport.clearBoard();
						viewport.setGameActive(true);
					}
					return Promise.resolve({ success: true });
				}
			},

			// Make a move at position
			makeMove: (x: number, y: number, z: number) => {
				if (gameMode.value === "vs-people") {
					return new Promise((resolve) => {
						socketApi.makeMove(x, y, z, (response: any) => {
							resolve(response);
						});
					});
				} else {
					const result = gameStore.makeMove(x, y, z);
					if (result.success && viewport) {
						viewport.addStone(x, y, z, gameStore.opponentPlayer);
					}
					return Promise.resolve(result);
				}
			},

			// Pass turn
			pass: () => {
				if (gameMode.value === "vs-people") {
					socketApi.pass();
					return Promise.resolve({ success: true });
				} else {
					const success = gameStore.pass();
					return Promise.resolve({ success });
				}
			},

			// Fetch room list
			fetchRoomList: () => {
				return new Promise((resolve) => {
					socketApi.listRooms((response: any) => {
						resolve(response);
					});
				});
			},

			// Join a room
			joinRoom: (roomId: string) => {
				return new Promise((resolve) => {
					socketApi.joinRoom(roomId, playerStore.nickname, preferredColor.value, (response: any) => {
						if (response.success) {
							playerStore.setRoomId(roomId);
							playerStore.connectionStatus = "connected";
						}
						resolve(response);
					});
				});
			},

			// Create new room
			createRoom: () => {
				return new Promise((resolve) => {
					socketApi.createRoom(playerStore.nickname, preferredColor.value, (response: any) => {
						if (response.success && response.roomId) {
							playerStore.setRoomId(response.roomId);
							playerStore.connectionStatus = "connected";
						}
						resolve(response);
					});
				});
			},

			// Set board shape
			setBoardShape: (shapeStr: string) => {
				selectedBoardShape.value = shapeStr;
				return { success: true, shape: shapeStr };
			}
		};
		console.log("[TrigoView] Testing API exposed at window.trigoApi");
	});

	// Watch for game mode changes and initialize modes as needed
	watch(gameMode, (newMode, oldMode) => {
		console.log(`[TrigoView] Game mode changed: ${oldMode} -> ${newMode}`);

		// Cleanup previous mode
		if (oldMode === "vs-people") {
			console.log("[TrigoView] Switching away from VS People mode, cleaning up...");
			cleanupVsPeopleMode();
		}

		// Initialize new mode
		if (newMode === "vs-people") {
			console.log("[TrigoView] Switching to VS People mode, initializing...");
			initializeVsPeopleMode();
		} else if (newMode === "vs-ai" && !aiReady.value) {
			console.log("[TrigoView] Switching to VS AI mode, initializing AI agent...");
			aiAgent.initialize()
				.then(() => {
					// After AI is ready, if it's AI's turn, generate move
					if (gameStarted.value && currentPlayer.value === aiPlayerColor.value) {
						setTimeout(() => {
							generateAIMove();
						}, 100);
					}
				})
				.catch((err) => {
					console.error("[TrigoView] Failed to initialize AI agent:", err);
				});
		}
	});

	onUnmounted(() => {
		console.log("TrigoDemo component unmounted");

		// Remove keyboard shortcuts
		window.removeEventListener("keydown", handleKeyPress);

		// Cleanup VS People mode if active
		cleanupVsPeopleMode();

		// Disconnect ResizeObserver
		if (resizeObserver) {
			resizeObserver.disconnect();
			resizeObserver = null;
			console.log("ResizeObserver disconnected");
		}

		// Cleanup Three.js resources
		if (viewport) {
			viewport.destroy();
			viewport = null;
		}
	});

	// Keyboard shortcuts handler
	const handleKeyPress = (event: KeyboardEvent) => {
		// Ignore if typing in an input field
		if (
			event.target instanceof HTMLInputElement ||
			event.target instanceof HTMLTextAreaElement
		) {
			return;
		}

		switch (event.key.toLowerCase()) {
			case "p": // Pass
				if (gameStarted.value) {
					pass();
				}
				break;
			case "n": // New game
				newGame();
				break;
			case "r": // Resign
				if (gameStarted.value) {
					resign();
				}
				break;
			case "arrowleft": // Previous move
				previousMove();
				event.preventDefault();
				break;
			case "arrowright": // Next move
				nextMove();
				event.preventDefault();
				break;
			case "t": // Compute territory
				if (gameStarted.value) {
					computeTerritory();
				}
				break;
		}
	};

	// TGN Modal Methods
	const selectAllTGN = (event: Event) => {
		const textarea = event.target as HTMLTextAreaElement;
		textarea.select();
	};

	const copyTGN = async () => {
		try {
			// Try modern clipboard API first
			if (navigator.clipboard && navigator.clipboard.writeText) {
				await navigator.clipboard.writeText(tgnContent.value);
				alert("TGN copied to clipboard!");
			} else {
				// Fallback for older browsers or non-secure contexts
				const textarea = document.createElement("textarea");
				textarea.value = tgnContent.value;
				textarea.style.position = "fixed";
				textarea.style.opacity = "0";
				document.body.appendChild(textarea);
				textarea.select();

				try {
					document.execCommand("copy");
					alert("TGN copied to clipboard!");
				} catch (fallbackErr) {
					console.error("Fallback copy failed:", fallbackErr);
					alert("Failed to copy TGN. Please select and copy manually.");
				} finally {
					document.body.removeChild(textarea);
				}
			}
		} catch (err) {
			console.error("Failed to copy TGN:", err);
			alert("Failed to copy TGN. Please select and copy manually.");
		}
	};
</script>

<style lang="scss" scoped>
	.trigo-view {
		display: flex;
		flex-direction: column;
		height: 100%;
		background-color: #404040;
		color: #e0e0e0;
		overflow: hidden;

		.view-header {
			display: flex;
			justify-content: space-between;
			align-items: center;
			padding: 1rem 2rem;
			background: linear-gradient(135deg, #505050 0%, #454545 100%);
			border-bottom: 2px solid #606060;
			box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);

			.view-status {
				display: flex;
				gap: 2rem;
				align-items: center;

				.turn-indicator {
					padding: 0.5rem 1rem;
					border-radius: 8px;
					font-weight: 600;
					transition: all 0.3s ease;

					&.black {
						background-color: #2c2c2c;
						color: #fff;
						box-shadow: 0 0 10px rgba(255, 255, 255, 0.3);
					}

					&.white {
						background-color: #f0f0f0;
						color: #000;
						box-shadow: 0 0 10px rgba(240, 240, 240, 0.3);
					}
				}

				.move-count {
					font-size: 1rem;
					color: #a0a0a0;
				}

				// VS AI Mode Styles
				&.ai-mode {
					.player-info,
					.ai-status {
						display: flex;
						align-items: center;
						gap: 0.5rem;
						padding: 0.5rem 1rem;
						background-color: #3a3a3a;
						border-radius: 8px;
						border: 2px solid transparent;
						transition: all 0.3s ease;

						&.on-turn {
							background-color: #4a4a4a;
							border-color: #60a5fa;
							box-shadow: 0 0 12px rgba(96, 165, 250, 0.4);
						}
					}

					.player-label,
					.ai-indicator {
						color: #a0a0a0;
						font-weight: 500;
					}

					.stone-icon {
						width: 20px;
						height: 20px;
						border-radius: 50%;
						flex-shrink: 0;

						&.black {
							background-color: #2c2c2c;
							border: 2px solid #fff;
						}

						&.white {
							background-color: #f0f0f0;
							border: 2px solid #000;
						}
					}

					.ai-level {
						color: #60a5fa;
						font-weight: 600;

						&.ai-thinking {
							color: #fbbf24;
							animation: pulse 1.5s ease-in-out infinite;
						}

						&.ai-error {
							color: #ef4444;
						}
					}

					.ai-time {
						color: #9ca3af;
						font-size: 0.875rem;
						font-style: italic;
					}

					.btn-swap-colors {
						padding: 0.4rem 0.8rem;
						background-color: #4b5563;
						color: #e5e7eb;
						border: none;
						border-radius: 6px;
						cursor: pointer;
						font-size: 0.875rem;
						font-weight: 600;
						transition: all 0.2s ease;

						&:hover {
							background-color: #6b7280;
							transform: translateY(-1px);
						}

						&:active {
							transform: translateY(0);
						}
					}
				}

				// VS People Mode Styles
				&.people-mode {
					.room-info {
						display: flex;
						align-items: center;
						gap: 0.5rem;
						padding: 0.5rem 1rem;
						background-color: #3a3a3a;
						border-radius: 8px;
					}

					.room-label {
						color: #a0a0a0;
						font-weight: 500;
					}

					.room-code {
						color: #e94560;
						font-weight: 700;
						font-family: monospace;
						font-size: 1.1rem;
					}

					.btn-copy-room {
						padding: 0.25rem 0.5rem;
						background-color: transparent;
						border: 1px solid #606060;
						border-radius: 4px;
						cursor: pointer;
						font-size: 0.9rem;
						transition: all 0.2s ease;

						&:hover {
							background-color: #505050;
							border-color: #808080;
						}
					}

					.players-info {
						display: flex;
						align-items: center;
						gap: 0.75rem;
						padding: 0.5rem 1rem;
						background-color: #3a3a3a;
						border-radius: 8px;
					}

					.player-display {
						transition: all 0.3s ease;

						&.on-turn {
							filter: brightness(1.3);
						}
					}

					.player-name {
						color: #e0e0e0;
						font-weight: 600;
					}

					.waiting-text {
						color: #9ca3af;
						font-style: italic;
					}

					.vs-divider {
						color: #606060;
						font-weight: 500;
					}

					.connection-status {
						padding: 0.5rem 1rem;
						border-radius: 8px;
						font-weight: 600;
						font-size: 0.9rem;

						&.connected {
							background-color: rgba(74, 222, 128, 0.15);
							color: #4ade80;
						}

						&.disconnected {
							background-color: rgba(239, 68, 68, 0.15);
							color: #ef4444;
						}
					}
				}

				// Library Mode Styles
				&.library-mode {
					.game-info {
						display: flex;
						align-items: center;
						gap: 1rem;
						padding: 0.5rem 1rem;
						background-color: #3a3a3a;
						border-radius: 8px;
					}

					.game-title {
						color: #e0e0e0;
						font-weight: 600;
						font-size: 1.1rem;
					}

					.game-date {
						color: #a0a0a0;
						font-weight: 500;
						font-family: monospace;
					}

					.library-actions {
						display: flex;
						gap: 0.5rem;
					}

					.btn-library {
						padding: 0.5rem 1rem;
						border: none;
						border-radius: 8px;
						font-weight: 600;
						font-size: 0.9rem;
						cursor: pointer;
						transition: all 0.3s ease;

						&.btn-load {
							background-color: #2d4059;
							color: #e0e0e0;

							&:hover {
								background-color: #3d5069;
								transform: translateY(-2px);
								box-shadow: 0 4px 12px rgba(45, 64, 89, 0.4);
							}
						}

						&.btn-export {
							background-color: #e94560;
							color: #fff;

							&:hover {
								background-color: #f95670;
								transform: translateY(-2px);
								box-shadow: 0 4px 12px rgba(233, 69, 96, 0.4);
							}
						}
					}
				}
			}
		}

		.header-controls {
			display: flex;
			align-items: center;
			gap: 0.75rem;
			margin-left: auto;

			.board-shape-select,
			.color-preference-select {
				background: rgba(0, 0, 0, 0.3);
				border: 1px solid rgba(255, 255, 255, 0.3);
				border-radius: 4px;
				color: #fff;
				padding: 0.4rem 0.6rem;
				font-size: 0.9rem;
				cursor: pointer;
				transition: background 0.2s;

				&:hover {
					background: rgba(0, 0, 0, 0.4);
				}

				&:disabled {
					opacity: 0.5;
					cursor: not-allowed;
				}

				// Ensure dropdown options are readable
				option {
					background: #3a3a3a;
					color: #e0e0e0;
				}
			}

			.color-preference-select {
				min-width: 130px;
			}

			.board-shape-select {
				min-width: 90px;
			}

			.btn-reset {
				background: #e94560;
				color: white;
				border: none;
				border-radius: 4px;
				padding: 0.4rem 1rem;
				font-size: 0.9rem;
				font-weight: 600;
				cursor: pointer;
				transition: background 0.2s;

				&:hover {
					background: #d63850;
				}

				&:active {
					background: #c02040;
				}
			}
		}

		.view-body {
			display: flex;
			flex: 1;
			overflow: hidden;

			.board-container {
				flex: 1;
				display: flex;
				align-items: center;
				justify-content: center;
				background-color: #484848;
				padding: 1rem;
				position: relative;

				.viewport-wrapper {
					width: 100%;
					height: 100%;
					position: relative;
					border-radius: 8px;
					overflow: hidden;
					box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);

					.viewport-canvas {
						width: 100%;
						height: 100%;
						display: block;
						background-color: #50505a;
					}

					.viewport-overlay {
						position: absolute;
						top: 0;
						left: 0;
						width: 100%;
						height: 100%;
						display: flex;
						align-items: center;
						justify-content: center;
						pointer-events: none;

						.loading-text {
							color: rgba(255, 255, 255, 0.5);
							font-size: 1.2rem;
							animation: pulse 2s ease-in-out infinite;
						}
					}

					.inspect-tooltip {
						position: absolute;
						top: 1rem;
						left: 1rem;
						background-color: rgba(255, 241, 176, 0.95);
						color: #111;
						padding: 0.5rem 1rem;
						border-radius: 8px;
						font-size: 0.9rem;
						font-weight: 600;
						pointer-events: none;
						box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
						z-index: 100;

						.tooltip-content {
							display: flex;
							align-items: center;
							gap: 0.5rem;

							.tooltip-label {
								white-space: nowrap;
							}

							.tooltip-divider {
								color: #888;
							}
						}
					}
				}
			}

			.controls-panel {
				width: 320px;
				background-color: #3a3a3a;
				border-left: 2px solid #606060;
				display: flex;
				flex-direction: column;
				overflow: hidden;
				box-shadow: -4px 0 16px rgba(0, 0, 0, 0.3);

				.panel-section {
					padding: 0.8rem;
					border-bottom: 1px solid #505050;
					position: relative;

					.section-title {
						font-size: 0.7rem;
						font-weight: 600;
						color: #f0bcc5;
						text-transform: uppercase;
						letter-spacing: 1px;
						position: absolute;
						top: 0;
						left: 0.8rem;
						opacity: 0;
						transition: opacity 0.3s ease-in;
					}

					&:hover .section-title {
						opacity: 0.6;
					}
				}

				.score-section {
					// Default style (captured mode) - lighter background
					.score-display {
						display: flex;
						gap: 0.5rem;
						margin-bottom: 1rem;

						.score-button {
							flex: 1;
							display: flex;
							align-items: center;
							justify-content: center;
							gap: 0.5rem;
							padding: 1rem;
							border: 2px solid #505050;
							border-radius: 8px;
							background-color: #484848;
							cursor: default;
							transition: all 0.3s ease;

							&.black {
								.color-indicator {
									background-color: #2c2c2c;
									border: 2px solid #fff;
								}
							}

							&.white {
								.color-indicator {
									background-color: #f0f0f0;
									border: 2px solid #000;
								}
							}

							.color-indicator {
								width: 24px;
								height: 24px;
								border-radius: 50%;
							}

							.score {
								font-size: 1.5rem;
								font-weight: 700;
								color: #e0e0e0;
							}

							&:disabled {
								opacity: 0.5;
							}
						}
					}

					.compute-territory {
						width: 100%;
						padding: 0.75rem;
						background-color: #505050;
						color: #e0e0e0;
						border: none;
						border-radius: 8px;
						font-weight: 600;
						cursor: pointer;
						transition: all 0.3s ease;

						&:hover:not(:disabled) {
							background-color: #606060;
						}

						&:disabled {
							opacity: 0.5;
							cursor: not-allowed;
						}
					}

					// Territory mode - darker background with glow
					&.show-territory {
						.score-display .score-button {
							background-color: #3a3a3a;
							border-color: #606060;
							box-shadow: 0 0 12px rgba(233, 69, 96, 0.3);
						}
					}
				}

				.routine-section {
					flex: 1;
					display: flex;
					flex-direction: column;
					min-height: 0;

					.routine-content {
						flex: 1;
						overflow-y: auto;
						background-color: #2a2a2a;
						border-radius: 8px;
						padding: 0.5rem;

						.move-list {
							padding: 0;
							margin: 0;

							.move-row {
								display: grid;
								grid-template-columns: 30px 1fr 1fr;
								gap: 0.25rem;
								margin-bottom: 0.25rem;
								align-items: center;

								&.start-row {
									grid-template-columns: 30px 1fr;
									padding: 0.5rem;
									border-radius: 4px;
									cursor: pointer;
									transition: all 0.2s ease;

									&:hover {
										background-color: #484848;
									}

									&.active {
										background-color: #505050;
										border-left: 3px solid #e94560;
									}

									.open-label {
										font-weight: 700;
										color: #e94560;
										text-transform: uppercase;
										letter-spacing: 1px;
									}
								}

								.round-number {
									color: #808080;
									font-size: 0.9em;
									text-align: right;
									padding-right: 0.25rem;
								}

								.move-cell {
									padding: 0.5rem;
									border-radius: 4px;
									cursor: pointer;
									transition: all 0.2s ease;
									display: flex;
									align-items: center;
									gap: 0.5rem;
									background-color: #1a1a1a;

									&:hover:not(.empty) {
										background-color: #484848;
									}

									&.active {
										background-color: #505050;
										border-left: 3px solid #e94560;
									}

									&.empty {
										background-color: transparent;
										cursor: default;
									}

									.stone-icon {
										width: 16px;
										height: 16px;
										border-radius: 50%;
										flex-shrink: 0;

										&.black {
											background-color: #2c2c2c;
											border: 2px solid #fff;
										}

										&.white {
											background-color: #f0f0f0;
											border: 2px solid #000;
										}
									}

									.move-coords {
										color: #a0a0a0;
										font-family: monospace;
										font-size: 0.9em;
									}

									.move-label {
										color: #60a5fa;
										font-weight: 600;
										font-size: 0.85em;
										text-transform: lowercase;
									}
								}
							}
						}
					}
				}

				.controls-section {
					.control-buttons {
						display: flex;
						flex-direction: column;
						gap: 1rem;

						.play-controls,
						.history-controls {
							display: flex;
							gap: 0.5rem;
						}

						.btn {
							padding: 0.75rem 1.5rem;
							border: none;
							border-radius: 8px;
							font-weight: 600;
							cursor: pointer;
							transition: all 0.3s ease;
							flex: 1;

							&:disabled {
								opacity: 0.5;
								cursor: not-allowed;
							}

							&.btn-pass {
								background-color: #2d4059;
								color: #e0e0e0;

								&:hover:not(:disabled) {
									background-color: #3d5069;
								}
							}

							&.btn-resign {
								background-color: #c23b22;
								color: #fff;

								&:hover:not(:disabled) {
									background-color: #d44b32;
								}
							}

							&.btn-icon {
								background-color: #505050;
								color: #e0e0e0;
								padding: 0.75rem;
								font-size: 1.2rem;

								&:hover:not(:disabled) {
									background-color: #606060;
								}
							}
						}
					}
				}

			}
		}
	}

	/* TGN Button and Modal Styles */
	.btn-view-tgn {
		position: absolute;
		top: 0;
		right: 0.8rem;
		padding: 0.25rem 0.5rem;
		background-color: transparent;
		color: #a0a0a0;
		border: 1px solid #505050;
		border-radius: 4px;
		font-size: 0.65rem;
		font-weight: 600;
		text-transform: uppercase;
		letter-spacing: 0.5px;
		cursor: pointer;
		transition: all 0.2s ease;
		opacity: 0;

		&:hover {
			background-color: #505050;
			color: #e0e0e0;
			border-color: #606060;
		}
	}

	.routine-section:hover .btn-view-tgn {
		opacity: 1;
	}

	.tgn-modal {
		position: fixed;
		top: 0;
		left: 0;
		width: 100vw;
		height: 100vh;
		background-color: rgba(0, 0, 0, 0.7);
		display: flex;
		align-items: center;
		justify-content: center;
		z-index: 1000;
		backdrop-filter: blur(4px);

		.tgn-modal-content {
			background-color: #3a3a3a;
			border-radius: 12px;
			box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
			width: 90%;
			max-width: 600px;
			max-height: 80vh;
			display: flex;
			flex-direction: column;
			overflow: hidden;

			.tgn-modal-header {
				display: flex;
				justify-content: space-between;
				align-items: center;
				padding: 1rem 1.5rem;
				background-color: #2a2a2a;
				border-bottom: 1px solid #505050;

				h3 {
					margin: 0;
					font-size: 1.2rem;
					font-weight: 600;
					color: #e0e0e0;
				}

				.tgn-status {
					font-size: 0.85rem;
					font-weight: 600;
					padding: 0.4rem 0.8rem;
					border-radius: 4px;
					white-space: nowrap;
					transition: all 0.3s ease;

					&.idle {
						background-color: #505050;
						color: #a0a0a0;
					}

					&.valid {
						background-color: rgba(74, 222, 128, 0.15);
						color: #4ade80;
						border: 1px solid rgba(74, 222, 128, 0.4);
					}

					&.invalid {
						background-color: rgba(239, 68, 68, 0.15);
						color: #ef4444;
						border: 1px solid rgba(239, 68, 68, 0.4);
					}
				}

				.btn-close {
					background: none;
					border: none;
					color: #a0a0a0;
					font-size: 1.5rem;
					cursor: pointer;
					padding: 0;
					width: 32px;
					height: 32px;
					display: flex;
					align-items: center;
					justify-content: center;
					border-radius: 4px;
					transition: all 0.2s ease;

					&:hover {
						background-color: #505050;
						color: #e0e0e0;
					}
				}
			}

			.tgn-modal-body {
				flex: 1;
				padding: 1.5rem;
				overflow: auto;

				.tgn-textarea {
					width: 100%;
					height: 100%;
					min-height: 300px;
					background-color: #2a2a2a;
					color: #e0e0e0;
					border: 2px solid #505050;
					border-radius: 8px;
					padding: 1rem;
					font-family: "Courier New", Courier, monospace;
					font-size: 0.9rem;
					line-height: 1.6;
					resize: vertical;
					cursor: text;
					transition:
						border-color 0.3s ease,
						box-shadow 0.3s ease;

					&:focus {
						outline: none;
						border-color: #e94560;
					}

					&.valid {
						border-color: #4ade80;
						box-shadow: 0 0 8px rgba(74, 222, 128, 0.2);
					}

					&.invalid {
						border-color: #ef4444;
						box-shadow: 0 0 8px rgba(239, 68, 68, 0.2);
					}

					&.idle {
						border-color: #505050;
					}
				}
			}

			.tgn-modal-footer {
				display: flex;
				gap: 0.5rem;
				padding: 1rem 1.5rem;
				background-color: #2a2a2a;
				border-top: 1px solid #505050;

				.btn {
					flex: 1;
					padding: 0.75rem;
					border: none;
					border-radius: 8px;
					font-weight: 600;
					cursor: pointer;
					transition: all 0.3s ease;

					&:disabled {
						opacity: 0.5;
						cursor: not-allowed;
					}

					&.btn-apply {
						background-color: #4ade80;
						color: #000;

						&:hover:not(:disabled) {
							background-color: #22c55e;
							transform: translateY(-2px);
							box-shadow: 0 4px 12px rgba(74, 222, 128, 0.4);
						}
					}

					&.btn-copy {
						background-color: #e94560;
						color: #fff;

						&:hover {
							background-color: #f95670;
							transform: translateY(-2px);
							box-shadow: 0 4px 12px rgba(233, 69, 96, 0.4);
						}
					}

					&.btn-close-modal {
						background-color: #505050;
						color: #e0e0e0;

						&:hover {
							background-color: #606060;
						}
					}
				}
			}
		}
	}

	@keyframes pulse {
		0%,
		100% {
			opacity: 0.5;
		}
		50% {
			opacity: 1;
		}
	}

	/* Scrollbar styling */
	.controls-panel {
		&::-webkit-scrollbar {
			width: 8px;
		}

		&::-webkit-scrollbar-track {
			background: #2a2a2a;
		}

		&::-webkit-scrollbar-thumb {
			background: #505050;
			border-radius: 4px;

			&:hover {
				background: #606060;
			}
		}
	}

	.routine-content {
		&::-webkit-scrollbar {
			width: 6px;
		}

		&::-webkit-scrollbar-track {
			background: #2a2a2a;
		}

		&::-webkit-scrollbar-thumb {
			background: #505050;
			border-radius: 3px;

			&:hover {
				background: #606060;
			}
		}
	}

	// Animations
	@keyframes pulse {
		0%,
		100% {
			opacity: 1;
		}
		50% {
			opacity: 0.5;
		}
	}
</style>
