from __future__ import annotations

import json
import shutil
import time
from pathlib import Path
from typing import Any

from .paths import EnvironmentPaths


def _slugify(value: str | None, fallback: str) -> str:
    if not value:
        return fallback
    allowed = []
    for char in value.lower():
        if char.isalnum():
            allowed.append(char)
        elif char in {" ", "-", "_", "/"}:
            allowed.append("-")
    slug = "".join(allowed).strip("-")
    while "--" in slug:
        slug = slug.replace("--", "-")
    return slug or fallback


def build_session_paths(
    paths: EnvironmentPaths,
    initial_snapshot: dict[str, Any],
    label: str | None,
) -> tuple[str, Path, Path, Path]:
    timestamp = time.strftime("%Y%m%d-%H%M%S")
    session_id = "__".join(
        part
        for part in [
            timestamp,
            _slugify(initial_snapshot.get("track"), "track"),
            _slugify(initial_snapshot.get("car_model"), "car"),
            _slugify(label, "") if label else "",
        ]
        if part
    )
    session_dir = paths.sessions_root / session_id
    session_dir.mkdir(parents=True, exist_ok=True)
    return (
        session_id,
        session_dir,
        session_dir / "samples.jsonl",
        session_dir / "meta.json",
    )


def copy_session_artifacts(
    paths: EnvironmentPaths,
    session_dir: Path,
    *,
    since_unix_s: float,
) -> dict[str, str]:
    artifact_dir = session_dir / "artifacts"
    artifact_dir.mkdir(parents=True, exist_ok=True)
    candidates = [
        paths.aim_root / "telemetry_dump.act",
        paths.out_root / "race_out.json",
        paths.out_root / "laps.ini",
        paths.logs_root / "log.txt",
        paths.logs_root / "errors.txt",
        paths.logs_root / "custom_shaders_patch.log",
        paths.logs_root / "launcher.log",
    ]
    ctelemetry_root = paths.documents_root / "ctelemetry" / "player"
    if ctelemetry_root.exists():
        candidates.extend(ctelemetry_root.iterdir())
    copied: dict[str, str] = {}
    for candidate in candidates:
        if not candidate.exists():
            continue
        if candidate.stat().st_mtime < since_unix_s - 30.0:
            continue
        destination = artifact_dir / candidate.name
        shutil.copy2(candidate, destination)
        copied[candidate.name] = str(destination)
    return copied


def write_json(path: Path, payload: dict[str, Any]) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
