from __future__ import annotations

import configparser
import os
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Any


def _first_existing(candidates: list[Path]) -> Path | None:
    for candidate in candidates:
        if candidate.exists():
            return candidate
    return None


def _read_ini_value(path: Path, section: str, key: str) -> str | None:
    if not path.exists():
        return None
    parser = configparser.ConfigParser()
    parser.read(path, encoding="utf-8")
    if not parser.has_section(section):
        return None
    return parser.get(section, key, fallback=None)


def _project_root() -> Path:
    return Path(__file__).resolve().parents[2]


@dataclass(slots=True)
class EnvironmentPaths:
    project_root: Path
    assetto_root: Path | None
    documents_root: Path
    cfg_root: Path
    logs_root: Path
    out_root: Path
    aim_root: Path
    content_manager_root: Path | None
    moza_pit_house_root: Path | None
    moza_telemetry_root: Path | None
    moza_pending_root: Path | None
    codex_config: Path
    sessions_root: Path
    runtime_root: Path
    plans_root: Path

    def to_dict(self) -> dict[str, Any]:
        data = asdict(self)
        return {
            key: str(value) if isinstance(value, Path) else value
            for key, value in data.items()
        }


def discover_environment(project_root: Path | None = None) -> EnvironmentPaths:
    project_root = project_root or _project_root()
    user_profile = Path(os.environ["USERPROFILE"])
    local_app_data = Path(os.environ["LOCALAPPDATA"])
    program_files_x86 = Path(os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)"))
    program_files = Path(os.environ.get("ProgramFiles", r"C:\Program Files"))

    assetto_root = _first_existing(
        [
            program_files_x86 / "Steam" / "steamapps" / "common" / "assettocorsa",
            program_files / "Steam" / "steamapps" / "common" / "assettocorsa",
            Path(r"C:\Steam\steamapps\common\assettocorsa"),
            Path(r"D:\Steam\steamapps\common\assettocorsa"),
            Path(r"E:\Steam\steamapps\common\assettocorsa"),
            Path(r"F:\Steam\steamapps\common\assettocorsa"),
        ]
    )

    documents_root = user_profile / "Documents" / "Assetto Corsa"
    cfg_root = documents_root / "cfg"
    logs_root = documents_root / "logs"
    out_root = documents_root / "out"
    aim_root = documents_root / "aim"
    content_manager_root = local_app_data / "AcTools Content Manager"
    if not content_manager_root.exists():
        content_manager_root = None
    moza_pit_house_root = local_app_data / "MOZA Pit House"
    if not moza_pit_house_root.exists():
        moza_pit_house_root = None
    moza_telemetry_root = (
        moza_pit_house_root / "Telemetry" if moza_pit_house_root is not None else None
    )
    if moza_telemetry_root is not None and not moza_telemetry_root.exists():
        moza_telemetry_root = None
    moza_pending_root = (
        moza_telemetry_root / "Pending" if moza_telemetry_root is not None else None
    )
    if moza_pending_root is not None and not moza_pending_root.exists():
        moza_pending_root = None

    return EnvironmentPaths(
        project_root=project_root,
        assetto_root=assetto_root,
        documents_root=documents_root,
        cfg_root=cfg_root,
        logs_root=logs_root,
        out_root=out_root,
        aim_root=aim_root,
        content_manager_root=content_manager_root,
        moza_pit_house_root=moza_pit_house_root,
        moza_telemetry_root=moza_telemetry_root,
        moza_pending_root=moza_pending_root,
        codex_config=Path(os.environ["USERPROFILE"]) / ".codex" / "config.toml",
        sessions_root=project_root / "data" / "sessions",
        runtime_root=project_root / "data" / "runtime",
        plans_root=project_root / "data" / "plans",
    )


def read_race_context(paths: EnvironmentPaths) -> dict[str, Any]:
    race_ini = paths.cfg_root / "race.ini"
    parser = configparser.ConfigParser()
    result: dict[str, Any] = {}
    if race_ini.exists():
        parser.read(race_ini, encoding="utf-8")
        result = {
            "track": parser.get("RACE", "TRACK", fallback=None),
            "track_config": parser.get("RACE", "CONFIG_TRACK", fallback=None),
            "car_model": parser.get("RACE", "MODEL", fallback=None),
            "skin": parser.get("RACE", "SKIN", fallback=None),
            "server_name": parser.get("REMOTE", "SERVER_NAME", fallback=None),
            "server_ip": parser.get("REMOTE", "SERVER_IP", fallback=None),
            "server_port": parser.get("REMOTE", "SERVER_PORT", fallback=None),
            "weather": parser.get("WEATHER", "NAME", fallback=None),
            "ambient_temp_c": parser.getfloat("TEMPERATURE", "AMBIENT", fallback=None),
            "road_temp_c": parser.getfloat("TEMPERATURE", "ROAD", fallback=None),
        }

    telemetry_user_ini = paths.cfg_root / "telemetry_user.ini"
    result["telemetry_preset"] = _read_ini_value(telemetry_user_ini, "USER", "PRESET")
    return result
