"""General utilities that are useful across runners."""
from __future__ import annotations

import json
import platform
import subprocess
import sys
from pathlib import Path
from typing import NamedTuple

# Configure path to import the environment configuration
sys.path.insert(0, str(Path(__file__).parents[1]))
import environment

# Reset the path
del sys.path[0]


class MatchData(NamedTuple):
    """
    Data about the current match.

    :param match_number: The current match number
    :param match_duration: The duration of the match in seconds
    :param video_enabled: Whether video recording is enabled
    :param video_resolution: The resolution of the video recording
    """

    match_number: int | None = None
    match_duration: int = environment.DEFAULT_MATCH_DURATION
    video_enabled: bool = True
    video_resolution: tuple[int, int] = (1920, 1080)


def get_robot_file(robot_zone: int) -> Path:
    """
    Get the path to the robot file for the given zone.

    :param robot_zone: The zone number
    :return: The path to the robot file
    :raises FileNotFoundError: If no robot controller is found for the given zone
    """
    robot_file = environment.ZONE_ROOT / f'zone_{robot_zone}' / 'robot.py'

    # Check if the robot file exists
    if not robot_file.exists():
        raise FileNotFoundError(f"No robot code to run for zone {robot_zone}")

    return robot_file


def get_game_mode() -> str:
    """
    Get the game mode from the game mode file.

    Default to 'dev' if the file does not exist.

    :return: The game mode
    """
    if environment.GAME_MODE_FILE.exists():
        game_mode = environment.GAME_MODE_FILE.read_text().strip()
    else:
        game_mode = 'dev'

    assert game_mode in ['dev', 'comp'], f'Invalid game mode: {game_mode}'

    return game_mode


def print_simulation_version() -> None:
    """
    Print the version of the simulator that is running.

    Uses a VERSION file in the root of the simulator to determine the version.
    For development, the version is uses the git describe command.

    The version is printed to the console.
    """
    version_file = environment.SIM_ROOT / 'VERSION'
    if version_file.exists():
        version = version_file.read_text().strip()
    else:
        try:
            version = subprocess.check_output(
                ['git', 'describe', '--tags', '--always'],
                cwd=str(environment.SIM_ROOT.resolve()),
            ).decode().strip()
        except subprocess.CalledProcessError:
            version = 'unknown'

    print(
        f"Running simulator version: {version} in Python {platform.python_version()} "
        f"({platform.system()}-{platform.machine()})"
    )


def get_match_data() -> MatchData:
    """Load the match data from the match data file."""
    match_data_file = environment.ARENA_ROOT / 'match.json'
    default_match_data = MatchData()

    if match_data_file.exists():
        # TODO error handling for invalid json
        raw_data = json.loads(match_data_file.read_text())
        match_data = MatchData(
            match_number=raw_data.get('match_number', default_match_data.match_number),
            match_duration=raw_data.get('duration', default_match_data.match_duration),
            video_enabled=(
                raw_data.get('recording_config', {})
                .get('enabled', default_match_data.video_enabled)
            ),
            video_resolution=(
                raw_data.get('recording_config', {})
                .get('video_resolution', default_match_data.video_resolution)
            ),
        )
    else:
        match_data = default_match_data

    return match_data
