from __future__ import annotations

from pathlib import Path
from typing import Any

from liverylab_core import preview_assets, project_types, saved_games_paths


CAP_OFFICIAL_PATHS_READY = "official_paths_ready"
CAP_SAVED_CARS_READY = "saved_cars_ready"
CAP_PREVIEW_ASSETS_READY = "preview_assets_ready"
CAP_FULL_EXTRACTED_CONTENT_READY = "full_extracted_content_ready"
CAP_ADVANCED_TOOLS_READY = "advanced_tools_ready"
CAP_OFFICIAL_FOLDER_CUSTOM_ASSETS_SUPPORTED = "official_folder_custom_assets_supported"

CAPABILITY_KEYS = (
    CAP_OFFICIAL_PATHS_READY,
    CAP_SAVED_CARS_READY,
    CAP_PREVIEW_ASSETS_READY,
    CAP_FULL_EXTRACTED_CONTENT_READY,
    CAP_ADVANCED_TOOLS_READY,
    CAP_OFFICIAL_FOLDER_CUSTOM_ASSETS_SUPPORTED,
)

CAPABILITY_LABELS = {
    CAP_OFFICIAL_PATHS_READY: "Official folders",
    CAP_SAVED_CARS_READY: "Saved cars",
    CAP_PREVIEW_ASSETS_READY: "Preview assets",
    CAP_FULL_EXTRACTED_CONTENT_READY: "Full extracted content",
    CAP_ADVANCED_TOOLS_READY: "Advanced tools",
    CAP_OFFICIAL_FOLDER_CUSTOM_ASSETS_SUPPORTED: "Official custom assets",
}

CAPABILITY_DESCRIPTIONS = {
    CAP_OFFICIAL_PATHS_READY: "Saved Games/ACE exists for official external livery folders.",
    CAP_SAVED_CARS_READY: "Saved Games/ACE/ProfileData exists for garage SavedCars lookup.",
    CAP_PREVIEW_ASSETS_READY: "Car-specific preview assets are available for 3D preview, UV export and Layer Studio tooling.",
    CAP_FULL_EXTRACTED_CONTENT_READY: "content/cars exists in the selected AC EVO root.",
    CAP_ADVANCED_TOOLS_READY: "Advanced extracted-content tools may be available.",
    CAP_OFFICIAL_FOLDER_CUSTOM_ASSETS_SUPPORTED: "Official external livery output can use Saved Games/ACE folders.",
}


def _bool_map(**values: bool) -> dict[str, bool]:
    return {key: bool(values.get(key, False)) for key in CAPABILITY_KEYS}


def _root_has_preview_assets(root: Path | None, car_content_path: str = "") -> bool:
    if root is None:
        return False
    content_cars = root / "content" / "cars"
    if not content_cars.exists():
        return False
    car_id = Path(str(car_content_path).replace("\\", "/")).name
    if car_id:
        car_root = root / "content" / "cars" / car_id
        return car_root.exists()
    return True


def _preview_asset_status(
    root: Path | None,
    car_content_path: str = "",
    livery_library_root: str | Path | None = None,
    official_livery_library_root: str | Path | None = None,
) -> dict[str, Any]:
    car_id = preview_assets.safe_car_id(car_content_path)
    official_library_status = preview_assets.status(official_livery_library_root, car_id) if official_livery_library_root else {}
    legacy_library_status = preview_assets.status(livery_library_root, car_id) if livery_library_root else {}
    library_status = official_library_status if official_library_status.get("ready") else legacy_library_status
    game_root_ready = _root_has_preview_assets(root, car_content_path)
    official_library_ready = bool(official_library_status and official_library_status.get("ready"))
    legacy_library_ready = bool(legacy_library_status and legacy_library_status.get("ready"))
    ready = bool(official_library_ready or legacy_library_ready or game_root_ready)
    source = ""
    if official_library_ready:
        source = "official_livery_library"
    elif legacy_library_ready:
        source = "livery_library"
    elif game_root_ready:
        source = "game_root"
    return {
        "ready": ready,
        "source": source,
        "carId": car_id,
        "library": library_status,
        "officialLibrary": official_library_status,
        "legacyLibrary": legacy_library_status,
        "gameRoot": {
            "ready": game_root_ready,
            "root": str(root) if root else "",
            "carContentPath": str(car_content_path or ""),
        },
    }


def _saved_games_ace_root() -> Path:
    return saved_games_paths.ace_root()


def official_external_liveries_root(saved_games_ace_root: str | Path | None = None) -> Path:
    ace_root = Path(saved_games_ace_root).expanduser() if saved_games_ace_root else _saved_games_ace_root()
    return ace_root / "ExternalLiveries"


def saved_cars_roots(saved_games_ace_root: str | Path | None = None) -> list[Path]:
    ace_root = Path(saved_games_ace_root).expanduser() if saved_games_ace_root else _saved_games_ace_root()
    profile_root = ace_root / "ProfileData"
    if not profile_root.exists():
        return []
    roots: list[Path] = []
    for profile in profile_root.iterdir():
        if not profile.is_dir():
            continue
        for relative in (Path("OpenData") / "SavedCars",):
            candidate = profile / relative
            if candidate.exists() and candidate.is_dir():
                roots.append(candidate)
    return roots


def saved_cars_deployment_roots(saved_games_ace_root: str | Path | None = None) -> list[Path]:
    """Return existing or safely inferable per-profile SavedCars targets."""
    ace_root = Path(saved_games_ace_root).expanduser() if saved_games_ace_root else _saved_games_ace_root()
    existing = saved_cars_roots(ace_root)
    if existing:
        return existing

    profile_root = ace_root / "ProfileData"
    if not profile_root.exists() or not profile_root.is_dir():
        return []

    roots: list[Path] = []
    for profile in profile_root.iterdir():
        if not profile.is_dir():
            continue
        open_data = profile / "OpenData"
        if open_data.exists() and open_data.is_dir():
            roots.append(open_data / "SavedCars")
    return roots


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


def capabilities_for_entry(
    entry: dict[str, Any] | None,
    game_root: str | Path | None = None,
    saved_games_ace_root: str | Path | None = None,
    livery_library_root: str | Path | None = None,
    official_livery_library_root: str | Path | None = None,
) -> dict[str, bool]:
    data = entry if isinstance(entry, dict) else {}
    project_type = project_types.project_type_for_entry(data)
    root = _root_path(game_root or data.get("game_root"))
    full_extract_ready = bool(root and (root / "content" / "cars").exists())
    official_project = project_type == project_types.PROJECT_TYPE_OFFICIAL_EXTERNAL_LIVERY
    preview_status = _preview_asset_status(
        root,
        str(data.get("car_content_path") or ""),
        livery_library_root,
        official_livery_library_root if official_project else None,
    )
    preview_ready = bool(preview_status.get("ready"))

    ace_root = Path(saved_games_ace_root).expanduser() if saved_games_ace_root else _saved_games_ace_root()
    official_paths_ready = ace_root.exists()
    saved_cars_ready = bool(saved_cars_roots(ace_root))

    return _bool_map(
        official_paths_ready=official_paths_ready,
        saved_cars_ready=saved_cars_ready,
        preview_assets_ready=preview_ready,
        full_extracted_content_ready=full_extract_ready,
        advanced_tools_ready=full_extract_ready and project_type == project_types.PROJECT_TYPE_ADVANCED_EXTRACTED_CONTENT,
        official_folder_custom_assets_supported=official_project and official_paths_ready,
    )


def capability_details_for_entry(
    entry: dict[str, Any] | None,
    game_root: str | Path | None = None,
    saved_games_ace_root: str | Path | None = None,
    livery_library_root: str | Path | None = None,
    official_livery_library_root: str | Path | None = None,
) -> dict[str, Any]:
    data = entry if isinstance(entry, dict) else {}
    project_type = project_types.project_type_for_entry(data)
    official_project = project_type == project_types.PROJECT_TYPE_OFFICIAL_EXTERNAL_LIVERY
    root = _root_path(game_root or data.get("game_root"))
    ace_root = Path(saved_games_ace_root).expanduser() if saved_games_ace_root else _saved_games_ace_root()
    car_content_path = str(data.get("car_content_path") or "")
    return {
        "previewAssets": _preview_asset_status(
            root,
            car_content_path,
            livery_library_root,
            official_livery_library_root if official_project else None,
        ),
        "officialPaths": {
            "savedGamesAceRoot": str(ace_root),
            "externalLiveriesRoot": str(official_external_liveries_root(ace_root)),
        },
        "savedCarsRoots": [str(path) for path in saved_cars_roots(ace_root)],
    }


def capability_rows(capabilities: dict[str, Any] | None) -> list[dict[str, Any]]:
    values = capabilities if isinstance(capabilities, dict) else {}
    return [
        {
            "key": key,
            "label": CAPABILITY_LABELS.get(key, key),
            "description": CAPABILITY_DESCRIPTIONS.get(key, ""),
            "ready": bool(values.get(key, False)),
        }
        for key in CAPABILITY_KEYS
    ]


def environment_state(
    game_root: str | Path | None = None,
    project_type: str | None = None,
    car_content_path: str = "",
    saved_games_ace_root: str | Path | None = None,
    livery_library_root: str | Path | None = None,
    official_livery_library_root: str | Path | None = None,
) -> dict[str, Any]:
    normalized_type = project_types.normalize_project_type(project_type)
    root = _root_path(game_root)
    ace_root = Path(saved_games_ace_root).expanduser() if saved_games_ace_root else _saved_games_ace_root()
    external_root = official_external_liveries_root(ace_root)
    saved_roots = saved_cars_roots(ace_root)
    entry = {
        "project_type": normalized_type,
        "game_root": str(root) if root else "",
        "car_content_path": car_content_path,
    }
    capabilities = capabilities_for_entry(
        entry,
        root,
        saved_games_ace_root=ace_root,
        livery_library_root=livery_library_root,
        official_livery_library_root=official_livery_library_root,
    )
    capability_details = capability_details_for_entry(
        entry,
        root,
        saved_games_ace_root=ace_root,
        livery_library_root=livery_library_root,
        official_livery_library_root=official_livery_library_root,
    )
    return {
        "projectType": normalized_type,
        "gameRoot": str(root) if root else "",
        "savedGamesAceRoot": str(ace_root),
        "externalLiveriesRoot": str(external_root),
        "externalLiveriesRootExists": external_root.exists(),
        "savedCarsRoots": [str(path) for path in saved_roots],
        "savedCarsRootCount": len(saved_roots),
        "capabilities": capabilities,
        "capabilityDetails": capability_details,
        "capabilityRows": capability_rows(capabilities),
    }
