from __future__ import annotations

from pathlib import Path
from typing import Any

from liverylab_core import official_external_liveries, official_saved_cars, package_state, project_capabilities, saved_games_paths


RUNTIME_OFFICIAL = "official"
RUNTIME_ADVANCED = "advanced"
RUNTIME_MIXED = "mixed"
RUNTIME_UNKNOWN = "unknown"

KNOWN_RUNTIMES = {
    RUNTIME_OFFICIAL,
    RUNTIME_ADVANCED,
    RUNTIME_MIXED,
    RUNTIME_UNKNOWN,
}


def _path(value: str | Path | None) -> Path | None:
    text = str(value or "").strip()
    if not text:
        return None
    return Path(text).expanduser()


def _file_count(root: Path, pattern: str) -> int:
    if not root.exists() or not root.is_dir():
        return 0
    try:
        return sum(1 for item in root.glob(pattern) if item.is_file())
    except Exception:
        return 0


def _dir_count(root: Path) -> int:
    if not root.exists() or not root.is_dir():
        return 0
    try:
        return sum(1 for item in root.iterdir() if item.is_dir())
    except Exception:
        return 0


def _external_livery_count(root: Path) -> int:
    if not root.exists() or not root.is_dir():
        return 0
    try:
        return sum(
            1
            for path in root.glob(f"*/{official_external_liveries.EXTERNAL_LIVERY_JSON}")
            if path.is_file()
        )
    except Exception:
        return 0


def _saved_cars_summary(saved_games_ace_root: str | Path | None) -> dict[str, Any]:
    roots = project_capabilities.saved_cars_roots(saved_games_ace_root)
    file_count = 0
    errors: list[str] = []
    for root in roots:
        try:
            file_count += sum(
                1
                for item in root.glob(f"*{official_external_liveries.SAVED_CAR_SUFFIX}")
                if item.is_file()
            )
        except Exception as exc:
            errors.append(f"{root}: {exc}")

    custom_scan = official_saved_cars.scan_saved_cars(
        saved_games_ace_root=saved_games_ace_root,
        project_entries=[],
        custom_only=True,
    )
    return {
        "roots": [str(root) for root in roots],
        "rootCount": len(roots),
        "fileCount": file_count,
        "customFileCount": int(custom_scan.get("itemCount") or 0),
        "hiddenGarageCount": int(custom_scan.get("hiddenGarageCount") or 0),
        "errors": [*errors, *list(custom_scan.get("errors") or [])],
    }


def _advanced_artifact_summary(root: Path | None) -> dict[str, Any]:
    if root is None:
        return {
            "contentCarsCount": 0,
            "customGridsBridgePresent": False,
            "uiHookPresent": False,
            "notes": [],
        }

    content_cars = root / "content" / "cars"
    ui_root = root / "ui"
    notes: list[str] = []
    if content_cars.exists():
        notes.append("Loose content/cars exists.")
    return {
        "contentCarsCount": _dir_count(content_cars),
        "customGridsBridgePresent": (ui_root / "custom_grid_bridge").exists(),
        "uiHookPresent": (ui_root / "index.html").exists() or (ui_root / "index.html.backup").exists(),
        "notes": notes,
    }


def _classify_runtime(
    package: dict[str, Any],
    advanced: dict[str, Any],
    official: dict[str, Any],
) -> tuple[str, list[str], list[str], list[str]]:
    reasons: list[str] = []
    warnings: list[str] = []
    blockers: list[str] = []

    active_package = bool(package.get("activeExists"))
    disabled_package = bool(package.get("disabledExists"))
    content_cars = bool(package.get("contentCarsExists"))
    external_ready = bool(official.get("externalLiveriesRootExists"))
    saved_cars_ready = int(official.get("savedCarsRootCount") or 0) > 0

    if active_package:
        reasons.append("content.kspkg is active.")
    if disabled_package:
        reasons.append("A valid renamed or LiveryLab-disabled AC EVO content package was found.")
    if content_cars:
        reasons.append("Loose content/cars exists.")
    if external_ready:
        reasons.append("Saved Games/ACE/ExternalLiveries exists.")
    if saved_cars_ready:
        reasons.append("Profile SavedCars folders exist.")

    if active_package and disabled_package:
        blockers.append(
            "Active and disabled AC EVO content packages were detected. Steam may have updated AC EVO while content.kspkg was disabled. "
            "Keep the active package and resolve the older renamed copy before switching runtimes."
        )
        return RUNTIME_MIXED, reasons, warnings, blockers

    if bool(package.get("disabledAmbiguous")):
        blockers.append("Multiple valid renamed AC EVO content packages were found.")
        return RUNTIME_UNKNOWN, reasons, warnings, blockers

    if active_package:
        if content_cars:
            warnings.append(
                "content.kspkg is active while loose content/cars also exists. Official writes stay enabled; loose content is treated as inactive for the supported official runtime."
            )
        if not external_ready:
            warnings.append("Official ExternalLiveries folder is missing or not created yet.")
        if not saved_cars_ready:
            warnings.append("No profile SavedCars folder was found yet.")
        return RUNTIME_OFFICIAL, reasons, warnings, blockers

    if disabled_package and content_cars:
        return RUNTIME_ADVANCED, reasons, warnings, blockers

    if content_cars:
        warnings.append("Loose content/cars exists, but content.kspkg is not active or tracked as disabled.")
        return RUNTIME_ADVANCED, reasons, warnings, blockers

    if external_ready or saved_cars_ready:
        warnings.append("Official Saved Games folders exist, but the AC EVO package state is missing or unknown.")
        return RUNTIME_UNKNOWN, reasons, warnings, blockers

    blockers.append("No recognizable official or advanced runtime signals were found.")
    return RUNTIME_UNKNOWN, reasons, warnings, blockers


def inspect_runtime_state(
    game_root: str | Path | None = None,
    *,
    saved_games_ace_root: str | Path | None = None,
    package_manifest_root: str | Path | None = None,
) -> dict[str, Any]:
    root = _path(game_root)
    ace_root = saved_games_paths.ace_root(saved_games_ace_root)
    package = package_state.content_package_status(root or "", package_manifest_root)
    external_root = project_capabilities.official_external_liveries_root(ace_root)
    saved_cars = _saved_cars_summary(ace_root)
    advanced = _advanced_artifact_summary(root)
    official = {
        "savedGamesAceRoot": str(ace_root),
        "savedGamesAceRootExists": ace_root.exists(),
        "externalLiveriesRoot": str(external_root),
        "externalLiveriesRootExists": external_root.exists(),
        "externalLiveryCount": _external_livery_count(external_root),
        "savedCarsRootCount": saved_cars["rootCount"],
        "savedCarFileCount": saved_cars["fileCount"],
        "customSavedCarFileCount": saved_cars["customFileCount"],
    }
    runtime, reasons, warnings, blockers = _classify_runtime(package, advanced, official)
    return {
        "runtime": runtime,
        "gameRoot": str(root or ""),
        "savedGamesAceRoot": str(ace_root),
        "readyForOfficialGameWrites": runtime == RUNTIME_OFFICIAL and not blockers,
        "readyForAdvancedGameWrites": runtime == RUNTIME_ADVANCED and not blockers,
        "requiresRuntimeSwitch": runtime in {RUNTIME_MIXED, RUNTIME_UNKNOWN},
        "reasons": reasons,
        "warnings": warnings,
        "blockers": blockers,
        "package": package,
        "official": official,
        "savedCars": saved_cars,
        "advanced": advanced,
    }
