from __future__ import annotations

import json
import hashlib
import shutil
import tempfile
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path
from typing import Any, Callable

from liverylab_core import export_sanitize, layer_studio, livery_categories, official_external_workflow, package_security, package_zip, project_types, update_backup, workflow_scopes


BUNDLE_TYPE = "liverylab_transfer_bundle"
CATEGORY_TYPE = "liverylab_transfer_category"
BUNDLE_MANIFEST = "bundle_manifest.json"
CATEGORY_MANIFEST = "manifest.json"
BUNDLE_VERSION = 2
CATEGORY_VERSION = 1
TRANSFER_MAX_ZIP_FILE_COUNT = 100000
TRANSFER_MAX_ZIP_TOTAL_UNCOMPRESSED_BYTES = 12 * 1024 * 1024 * 1024

CATEGORY_LABELS = {
    "app_settings": "App settings",
    "my_liveries": "My Liveries",
    "driver_profiles": "Driver profiles",
    "tyre_brands": "Tyre brands",
    "custom_grids": "Custom grids",
    "numberplates": "Numberplates",
    "layer_studio": "Layer Studio Library",
    "project_files": "Project files",
}

EXPORT_CATEGORY_IDS = tuple(key for key in CATEGORY_LABELS if key != "project_files")
ITEMIZED_CATEGORIES = {"my_liveries", "driver_profiles", "tyre_brands"}
SIMPLE_CATEGORIES = {"app_settings", "custom_grids", "numberplates", "layer_studio", "project_files"}
ProgressCallback = Callable[[dict[str, Any]], None]
PROJECT_EXTRA_INCLUDE_FILENAMES = {"plate_r.png"}
TRANSFER_TOP_LEVEL = {
    BUNDLE_MANIFEST,
    "UserData",
    "LiveryLibrary",
    "LiveryProjects",
    "OfficialLiveryLibrary",
    "OfficialLiveryProjects",
}
MACHINE_LOCAL_SETTING_KEYS = {
    "default_root_folder",
    "preview3d_project",
    "official_external_suppressed_source_ids",
}


@dataclass(frozen=True)
class TransferRoots:
    user_data: Path
    livery_library: Path
    livery_projects: Path
    package_export: Path
    temp: Path
    game_root: Path | None = None
    official_livery_library: Path | None = None
    official_livery_projects: Path | None = None

    def __post_init__(self) -> None:
        base = self.livery_projects.parent
        if self.official_livery_library is None:
            object.__setattr__(self, "official_livery_library", base / "OfficialLiveryLibrary")
        if self.official_livery_projects is None:
            object.__setattr__(self, "official_livery_projects", base / "OfficialLiveryProjects")


def _now_stamp() -> str:
    return datetime.now().strftime("%Y%m%d_%H%M%S")


def _short_bundle_stamp() -> str:
    return datetime.now().strftime("%y%m%d_%H%M")


def _json_ready(value: Any) -> Any:
    if isinstance(value, Path):
        return str(value)
    if isinstance(value, dict):
        return {str(key): _json_ready(item) for key, item in value.items()}
    if isinstance(value, (list, tuple, set)):
        return [_json_ready(item) for item in value]
    return value


def _read_json(path: Path, fallback: Any) -> Any:
    try:
        return json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        return fallback


def _write_json(path: Path, data: Any) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps(_json_ready(data), indent=2, ensure_ascii=False), encoding="utf-8")


def _norm_rel(path: str | Path) -> str:
    return str(path).replace("/", "\\").strip("\\")


def _safe_rel(rel: str) -> Path:
    text = str(rel or "").replace("\\", "/").strip("/")
    path = Path(text)
    if not text or path.is_absolute() or ".." in path.parts:
        raise ValueError(f"Unsafe transfer path: {rel}")
    return path


def _emit(progress: ProgressCallback | None, payload: dict[str, Any]) -> None:
    if progress is None:
        return
    try:
        progress(payload)
    except Exception:
        pass


def _transfer_zip_options() -> dict[str, int]:
    return {
        "max_file_count": TRANSFER_MAX_ZIP_FILE_COUNT,
        "max_total_uncompressed_bytes": TRANSFER_MAX_ZIP_TOTAL_UNCOMPRESSED_BYTES,
    }


def _copy_any(
    source: Path,
    target: Path,
    file_progress: Callable[[Path], None] | None = None,
    exclude: Callable[[Path], bool] | None = None,
) -> int:
    if not source.exists():
        return 0
    if source.is_dir():
        if target.exists():
            shutil.rmtree(target)
        target.mkdir(parents=True, exist_ok=True)
        copied = 0
        for file_path in _iter_files(source) or []:
            if exclude and exclude(file_path):
                continue
            rel = file_path.relative_to(source)
            destination = target / rel
            package_zip.copy_file(file_path, destination)
            copied += 1
            if file_progress:
                file_progress(file_path)
        return copied
    package_zip.copy_file(source, target)
    if file_progress:
        file_progress(source)
    return 1


def _iter_files(root: Path):
    if not root.exists():
        return
    if root.is_file():
        yield root
        return
    for path in sorted(root.rglob("*"), key=lambda item: item.as_posix().lower()):
        if any(part.lower() in update_backup.EXCLUDED_DIR_NAMES for part in path.parts):
            continue
        if path.is_file():
            yield path


def _count_files(path: Path) -> int:
    return sum(1 for _ in _iter_files(path) or [])


def _path_size(path: Path) -> int:
    total = 0
    for file_path in _iter_files(path) or []:
        try:
            total += file_path.stat().st_size
        except OSError:
            pass
    return total


def _relative_to_roots(path: Path, roots: TransferRoots) -> Path | None:
    for root_name, base in (
        ("UserData", roots.user_data),
        ("LiveryLibrary", roots.livery_library),
        ("LiveryProjects", roots.livery_projects),
        ("OfficialLiveryLibrary", roots.official_livery_library),
        ("OfficialLiveryProjects", roots.official_livery_projects),
    ):
        try:
            return Path(root_name) / path.resolve().relative_to(base.resolve())
        except Exception:
            continue
    return None


def _allowed_import_roots(roots: TransferRoots) -> tuple[Path, ...]:
    return (roots.user_data, roots.livery_library, roots.livery_projects, roots.official_livery_library, roots.official_livery_projects)


def _assert_import_target(roots: TransferRoots, target: Path, label: str = "transfer import target") -> Path:
    return package_security.assert_target_within_roots(target, _allowed_import_roots(roots), label=label)


def _target_for_rooted_rel(roots: TransferRoots, rel_path: Path, label: str = "transfer import target") -> Path:
    parts = rel_path.parts
    if not parts:
        raise ValueError("Transfer import target path is empty")
    if parts[0] == "UserData":
        target = roots.user_data.joinpath(*parts[1:])
    elif parts[0] == "LiveryLibrary":
        target = roots.livery_library.joinpath(*parts[1:])
    elif parts[0] == "LiveryProjects":
        target = roots.livery_projects.joinpath(*parts[1:])
    elif parts[0] == "OfficialLiveryLibrary":
        target = roots.official_livery_library.joinpath(*parts[1:])
    elif parts[0] == "OfficialLiveryProjects":
        target = roots.official_livery_projects.joinpath(*parts[1:])
    else:
        raise ValueError(f"Unsupported transfer import root: {parts[0]}")
    return _assert_import_target(roots, target, label)


def _rebase_managed_transfer_path(value: str, roots: TransferRoots) -> str:
    text = str(value or "")
    normalized = text.replace("\\", "/")
    parts = [part for part in normalized.split("/") if part]
    root_targets = {
        "userdata": roots.user_data,
        "liverylibrary": roots.livery_library,
        "liveryprojects": roots.livery_projects,
        "officialliverylibrary": roots.official_livery_library,
        "officialliveryprojects": roots.official_livery_projects,
    }
    for index, part in enumerate(parts):
        target_root = root_targets.get(part.lower())
        if target_root is None:
            continue
        path_like = (
            index == 0
            or normalized.startswith("/")
            or (parts and len(parts[0]) == 2 and parts[0][1] == ":")
        )
        if not path_like:
            return text
        return str(target_root.joinpath(*parts[index + 1 :]))
    return text


def _rebase_managed_transfer_paths(value: Any, roots: TransferRoots) -> Any:
    if isinstance(value, dict):
        rebased: dict[str, Any] = {}
        for key, item in value.items():
            clean_key = str(key)
            if clean_key.lower() in {"gameroot", "game_root"} and roots.game_root is not None and isinstance(item, str):
                rebased[clean_key] = str(roots.game_root)
            else:
                rebased[clean_key] = _rebase_managed_transfer_paths(item, roots)
        return rebased
    if isinstance(value, list):
        return [_rebase_managed_transfer_paths(item, roots) for item in value]
    if isinstance(value, str):
        return _rebase_managed_transfer_path(value, roots)
    return value


def _rebase_source_game_paths(value: Any, source_root: str, target_root: Path | None) -> Any:
    if not source_root or target_root is None:
        return value
    if isinstance(value, dict):
        return {str(key): _rebase_source_game_paths(item, source_root, target_root) for key, item in value.items()}
    if isinstance(value, list):
        return [_rebase_source_game_paths(item, source_root, target_root) for item in value]
    if not isinstance(value, str):
        return value
    source_normalized = source_root.replace("\\", "/").rstrip("/")
    value_normalized = value.replace("\\", "/")
    source_lower = source_normalized.lower()
    value_lower = value_normalized.lower()
    if value_lower == source_lower:
        return str(target_root)
    prefix = source_lower + "/"
    if not value_lower.startswith(prefix):
        return value
    suffix = [part for part in value_normalized[len(source_normalized) :].split("/") if part]
    return str(target_root.joinpath(*suffix))


def _rewrite_imported_json_paths(path: Path, roots: TransferRoots) -> int:
    if path.is_file():
        candidates = [path]
    elif path.is_dir():
        candidates = sorted(path.rglob("*.json"), key=lambda item: item.as_posix().lower())
    else:
        candidates = []
    rewritten = 0
    for candidate in candidates:
        if candidate.suffix.lower() != ".json":
            continue
        original = _read_json(candidate, None)
        if original is None:
            continue
        updated = _rebase_managed_transfer_paths(original, roots)
        if updated == original:
            continue
        _write_json(candidate, updated)
        rewritten += 1
    return rewritten


def _backup_target(target: Path, backup_root: Path, roots: TransferRoots) -> str:
    if not target.exists():
        return ""
    rel = _relative_to_roots(target, roots)
    if rel is None:
        return ""
    destination = backup_root / rel
    destination.parent.mkdir(parents=True, exist_ok=True)
    if target.is_dir():
        if destination.exists():
            return str(destination)
        destination.mkdir(parents=True, exist_ok=True)
        for child in _iter_files(target) or []:
            package_zip.copy_file(child, destination / child.relative_to(target))
    else:
        package_zip.copy_file(target, destination)
    return str(destination)


def _skin_registry_path(roots: TransferRoots) -> Path:
    return roots.livery_library / "my_skins.json"


def _coerce_my_skins(data: Any) -> list[dict[str, Any]]:
    if isinstance(data, dict):
        data = data.get("my_skins", [])
    if not isinstance(data, list):
        return []
    return [item for item in data if isinstance(item, dict)]


def _my_skins_registry_payload(items: list[dict[str, Any]]) -> dict[str, Any]:
    return {
        "formatVersion": 1,
        "app": {"name": "LiveryLab"},
        "updatedAt": datetime.now().isoformat(timespec="seconds"),
        "my_skins": items,
    }


def _load_my_skins(roots: TransferRoots) -> list[dict[str, Any]]:
    return _coerce_my_skins(_read_json(_skin_registry_path(roots), {}))


def _skin_local_root(roots: TransferRoots, entry: dict[str, Any]) -> Path:
    raw_local = str(entry.get("local_root") or "").strip()
    local = Path(raw_local) if raw_local else None
    if local is not None and local.exists():
        return local
    car = str(entry.get("car_model") or "").strip() or "car"
    skin = str(entry.get("skin_id") or "").strip() or "skin"
    return roots.livery_library / "LocalSkins" / car / skin


def _official_transfer_role(entry: dict[str, Any]) -> str:
    if project_types.project_type_for_entry(entry) != project_types.PROJECT_TYPE_OFFICIAL_EXTERNAL_LIVERY:
        return ""
    return official_external_workflow.role_for_entry(entry)


def _reset_transferred_entry_state(entry: dict[str, Any], target: Path, roots: TransferRoots) -> dict[str, Any]:
    data = export_sanitize.clean_my_skin_entry(entry, portable_paths=True)
    data = _rebase_managed_transfer_paths(data, roots)
    data["local_root"] = str(target)
    if roots.game_root is not None:
        data["game_root"] = str(roots.game_root)
    data["active"] = False
    details = dict(data.get("official_external") or {}) if isinstance(data.get("official_external"), dict) else {}
    if details:
        details["deploymentStatus"] = "local"
        details["savedCarFound"] = False
        details["savedCarPaths"] = []
        for key in (
            "deployment",
            "lastDeployment",
            "lastDeactivation",
            "activeFolder",
            "deployedFolder",
            "savedCarPath",
            "targetFolder",
        ):
            details.pop(key, None)
        data["official_external"] = details
    return data


def _rewrite_imported_skin_metadata(project_root: Path, entry: dict[str, Any]) -> bool:
    path = project_root / "liverylab_skin.json"
    payload = _read_json(path, None)
    if not isinstance(payload, dict):
        return False
    if isinstance(payload.get("skin"), dict):
        payload["skin"] = dict(entry)
    else:
        payload = dict(entry)
    _write_json(path, payload)
    return True


def _reset_imported_official_project_metadata(project_root: Path, roots: TransferRoots) -> bool:
    path = project_root / "official_external_project.json"
    payload = _read_json(path, None)
    if not isinstance(payload, dict):
        return False
    project = payload.get("project") if isinstance(payload.get("project"), dict) else {}
    car_model = str(project.get("carModel") or project_root.parent.name).strip()
    preview_root = roots.official_livery_library / "PreviewAssets" / "Derived" / car_model
    old_project = str((payload.get("previewAssets") or {}).get("projectFolder") or "") if isinstance(payload.get("previewAssets"), dict) else ""
    old_preview = str((payload.get("previewAssets") or {}).get("derivedRoot") or "") if isinstance(payload.get("previewAssets"), dict) else ""

    def rebase(value: Any) -> Any:
        if isinstance(value, dict):
            return {str(key): rebase(item) for key, item in value.items()}
        if isinstance(value, list):
            return [rebase(item) for item in value]
        if not isinstance(value, str):
            return value
        text = value
        for source, target in ((old_project, str(project_root)), (old_preview, str(preview_root))):
            if not source:
                continue
            variants = {source, source.replace("\\", "/"), source.replace("/", "\\")}
            for variant in sorted(variants, key=len, reverse=True):
                text = text.replace(variant, target)
        return text

    payload = rebase(payload)
    payload["deploymentStatus"] = "local"
    payload["deployment"] = {}
    payload["deploymentPreflight"] = {}
    payload["lastDeactivation"] = {}
    metadata = dict(payload.get("metadata") or {}) if isinstance(payload.get("metadata"), dict) else {}
    if (project_root / "livery_thumbnail.png").is_file():
        metadata["thumbnail"] = str(project_root / "livery_thumbnail.png")
    payload["metadata"] = metadata
    _write_json(path, payload)
    return True


def _is_legacy_numberplate_bake_path(path: Path) -> bool:
    return export_sanitize.is_legacy_numberplate_bake_path(path)


def _is_generated_thumbnail_ref(value: Any) -> bool:
    text = _norm_rel(str(value or "")).lower()
    return "\\generated\\thumbnails\\" in f"\\{text}"


def _is_generated_thumbnail_path(path: Path) -> bool:
    return _is_generated_thumbnail_ref(path)


def _exclude_non_portable_my_livery_path(path: Path) -> bool:
    return _is_legacy_numberplate_bake_path(path) or _is_generated_thumbnail_path(path)


def _strip_generated_thumbnail_metadata(entry: dict[str, Any]) -> dict[str, Any]:
    data = dict(entry)
    files = dict(data.get("files") or {}) if isinstance(data.get("files"), dict) else {}

    for kind in ("thumbnail", "thumbnail_mips"):
        if _is_generated_thumbnail_ref(files.get(kind)):
            files.pop(kind, None)

    for kind in ("thumbnails", "thumbnail_mips_list"):
        values = files.get(kind)
        rows = values if isinstance(values, list) else ([values] if values else [])
        kept = [str(row) for row in rows if str(row or "").strip() and not _is_generated_thumbnail_ref(row)]
        if kept:
            files[kind] = kept
        else:
            files.pop(kind, None)

    data["files"] = files
    return data


def _strip_disabled_numberplate_metadata(entry: dict[str, Any]) -> dict[str, Any]:
    return export_sanitize.clean_my_skin_entry(entry)


def _strip_disabled_numberplate_metadata_file(path: Path) -> None:
    data = _read_json(path, None)
    if isinstance(data, dict):
        cleaned = export_sanitize.clean_my_skin_metadata_payload(
            _strip_generated_thumbnail_metadata(data),
            portable_paths=True,
        )
        if cleaned != data:
            _write_json(path, cleaned)


def _entry_file_rel_values(entry: dict[str, Any], kinds: set[str]) -> list[tuple[str, str]]:
    files = entry.get("files") if isinstance(entry.get("files"), dict) else {}
    rows: list[tuple[str, str]] = []
    for kind in kinds:
        value = files.get(kind)
        values = value if isinstance(value, list) else [value]
        for item in values:
            text = str(item or "").strip()
            if text:
                rows.append((kind, text))
    return rows


def _hydrate_my_livery_game_files(roots: TransferRoots, entry: dict[str, Any], staged_local_root: Path) -> int:
    game_root = roots.game_root
    if game_root is None or not game_root.exists():
        return 0
    hydrate_kinds = {
        "carfinalstate",
        "carfinalstates",
    }
    copied = 0
    seen: set[str] = set()
    for _kind, rel in _entry_file_rel_values(entry, hydrate_kinds):
        try:
            rel_path = _safe_rel(rel)
        except ValueError:
            continue
        key = _norm_rel(rel_path).lower()
        if key in seen:
            continue
        seen.add(key)
        target = staged_local_root / rel_path
        if target.exists():
            continue
        source = game_root / rel_path
        if not source.exists() or not source.is_file():
            continue
        package_zip.copy_file(source, target)
        copied += 1
    return copied


def _local_entry_file_exists(local_root: Path, rel: str) -> bool:
    try:
        rel_path = _safe_rel(rel)
    except ValueError:
        return False
    return (local_root / rel_path).exists()


def _sanitize_optional_thumbnail_refs(entry: dict[str, Any], local_root: Path) -> tuple[dict[str, Any], list[dict[str, str]]]:
    data = dict(entry)
    files = dict(data.get("files") or {}) if isinstance(data.get("files"), dict) else {}
    missing: list[dict[str, str]] = []

    def filter_list(kind: str) -> None:
        values = files.get(kind)
        rows = values if isinstance(values, list) else ([values] if values else [])
        kept: list[str] = []
        for row in rows:
            rel = str(row or "").strip()
            if not rel:
                continue
            if _local_entry_file_exists(local_root, rel):
                kept.append(rel)
            else:
                missing.append({"kind": kind, "path": rel})
        if kept:
            files[kind] = kept
        else:
            files.pop(kind, None)

    def filter_scalar(kind: str) -> None:
        rel = str(files.get(kind) or "").strip()
        if not rel:
            files.pop(kind, None)
            return
        if not _local_entry_file_exists(local_root, rel):
            missing.append({"kind": kind, "path": rel})
            files.pop(kind, None)

    filter_list("thumbnails")
    filter_list("thumbnail_mips_list")
    filter_scalar("thumbnail")
    filter_scalar("thumbnail_mips")
    if not files.get("thumbnail") and isinstance(files.get("thumbnails"), list) and files["thumbnails"]:
        files["thumbnail"] = files["thumbnails"][0]
    if not files.get("thumbnail_mips") and isinstance(files.get("thumbnail_mips_list"), list) and files["thumbnail_mips_list"]:
        files["thumbnail_mips"] = files["thumbnail_mips_list"][0]
    data["files"] = files
    if missing:
        data["transfer_missing_optional_files"] = missing
    return data, missing


def _mandatory_transfer_missing_files(entry: dict[str, Any], local_root: Path) -> list[dict[str, str]]:
    missing: list[dict[str, str]] = []
    for kind, rel in _entry_file_rel_values(entry, {"carfinalstate", "carfinalstates"}):
        if not _local_entry_file_exists(local_root, rel):
            missing.append({"kind": kind, "path": rel})
    if project_types.project_type_for_entry(entry) == project_types.PROJECT_TYPE_OFFICIAL_EXTERNAL_LIVERY:
        details = entry.get("official_external") if isinstance(entry.get("official_external"), dict) else {}
        generated = details.get("generatedSavedCar") if isinstance(details.get("generatedSavedCar"), dict) else {}
        files = entry.get("files") if isinstance(entry.get("files"), dict) else {}
        rel = str(generated.get("relativePath") or files.get("saved_car") or "").strip()
        if rel and not _local_entry_file_exists(local_root, rel):
            missing.append({"kind": "saved_car", "path": rel})
    return missing


def _driver_manifests(roots: TransferRoots) -> list[Path]:
    root = roots.livery_library / "Drivers"
    return sorted(root.glob("*/*/manifest.json"), key=lambda path: path.as_posix().lower()) if root.exists() else []


def _tyre_manifests(roots: TransferRoots) -> list[Path]:
    root = roots.livery_library / "TyreBrands"
    return sorted(root.rglob("manifest.json"), key=lambda path: path.as_posix().lower()) if root.exists() else []


def _project_allowed_files(roots: TransferRoots) -> list[Path]:
    if not roots.livery_projects.exists():
        return []
    return [
        path
        for path in _iter_files(roots.livery_projects) or []
        if update_backup._project_file_allowed(path) and not _is_layer_studio_project_path(path)
    ]


def _is_layer_studio_project_path(path: Path) -> bool:
    return "layer-studio" in {str(part).lower() for part in path.parts}


def _layer_studio_project_files(roots: TransferRoots) -> list[Path]:
    if not roots.livery_projects.exists():
        return []
    return [
        path
        for path in _iter_files(roots.livery_projects) or []
        if _is_layer_studio_project_path(path) and path.suffix.lower() in {".json", ".png"}
    ]


def _layer_studio_library_root(roots: TransferRoots) -> Path:
    return roots.livery_library / "LayerStudioLibrary"


def _layer_studio_file_count(roots: TransferRoots) -> int:
    return _count_files(_layer_studio_library_root(roots))


def _layer_studio_size(roots: TransferRoots) -> int:
    return _path_size(_layer_studio_library_root(roots))


def _livery_project_root(roots: TransferRoots, entry: dict[str, Any]) -> Path:
    if project_types.project_type_for_entry(entry) == project_types.PROJECT_TYPE_OFFICIAL_EXTERNAL_LIVERY:
        local = Path(str(entry.get("local_root") or "")).expanduser()
        if str(entry.get("local_root") or "").strip() and local.exists():
            return local
        return roots.official_livery_projects / str(entry.get("car_model") or "car") / str(entry.get("skin_id") or "skin")
    car_model = str(entry.get("car_model") or "").strip() or "car"
    skin_id = str(entry.get("skin_id") or entry.get("display_name") or "").strip() or "skin"
    return roots.livery_projects / car_model / skin_id


def _livery_project_file_allowed(path: Path) -> bool:
    if path.suffix.lower() == ".carfinalstatewithconsumable":
        return True
    if _is_layer_studio_project_path(path):
        return path.suffix.lower() in {".json", ".png"}
    return update_backup._project_file_allowed(path) or path.name.lower() in PROJECT_EXTRA_INCLUDE_FILENAMES


def _iter_livery_project_files(project_root: Path):
    if not project_root.exists() or not project_root.is_dir():
        return
    for path in _iter_files(project_root) or []:
        if _livery_project_file_allowed(path):
            yield path


def _iter_layer_rows(rows: Any):
    for row in rows if isinstance(rows, list) else []:
        if not isinstance(row, dict):
            continue
        yield row
        yield from _iter_layer_rows(row.get("children"))


def _layer_studio_library_refs_in_project(project_root: Path) -> set[str]:
    refs: set[str] = set()
    layer_root = project_root / layer_studio.PROJECT_DIRNAME
    if not layer_root.exists():
        return refs
    for layers_path in sorted(layer_root.rglob(layer_studio.LAYERS_FILE_NAME), key=lambda item: item.as_posix().lower()):
        document = _read_json(layers_path, {})
        if not isinstance(document, dict):
            continue
        for layer in _iter_layer_rows(document.get("layers")):
            if str(layer.get("sourceType") or "project").strip().lower() != "library":
                continue
            asset_id = str(layer.get("source") or "").strip()
            if asset_id:
                refs.add(asset_id)
    return refs


def _write_layer_studio_library_subset(
    roots: TransferRoots,
    stage: Path,
    asset_ids: set[str],
    mark_file: Callable[[str, Path], None] | None = None,
    category: str = "my_liveries",
) -> int:
    if not asset_ids:
        return 0
    library_root = _layer_studio_library_root(roots)
    library = _read_json(library_root / layer_studio.LIBRARY_FILE_NAME, {})
    if not isinstance(library, dict):
        return 0
    assets = [
        dict(row)
        for row in library.get("assets", []) if isinstance(row, dict) and str(row.get("id") or "") in asset_ids
    ]
    if not assets:
        return 0
    group_ids = {str(row.get("groupId") or layer_studio.LIBRARY_DEFAULT_GROUP_ID) for row in assets}
    groups = [
        dict(row)
        for row in library.get("groups", []) if isinstance(row, dict) and str(row.get("id") or "") in group_ids
    ]
    if not any(str(row.get("id") or "") == layer_studio.LIBRARY_DEFAULT_GROUP_ID for row in groups):
        groups.insert(0, {
            "id": layer_studio.LIBRARY_DEFAULT_GROUP_ID,
            "name": "Ungrouped",
            "collapsed": False,
            "order": 0,
        })

    target_root = stage / "LiveryLibrary" / layer_studio.LIBRARY_DIRNAME
    target_assets_root = target_root / layer_studio.LIBRARY_ASSETS_DIRNAME
    target_assets_root.mkdir(parents=True, exist_ok=True)
    copied = 0
    kept_assets: list[dict[str, Any]] = []
    for asset in assets:
        file_rel = str(asset.get("file") or "").strip()
        if not file_rel:
            continue
        try:
            file_path = _safe_rel(file_rel)
        except ValueError:
            continue
        source = library_root / file_path
        if not source.is_file():
            continue
        package_zip.copy_file(source, target_root / file_path)
        if mark_file:
            mark_file(category, source)
        copied += 1
        kept_assets.append(asset)
    if not kept_assets:
        return 0
    _write_json(target_root / layer_studio.LIBRARY_FILE_NAME, {
        "version": 1,
        "type": "layer-studio-asset-library",
        "groups": groups,
        "assets": kept_assets,
    })
    copied += 1
    return copied


def _sha256_file(path: Path) -> str:
    digest = hashlib.sha256()
    with path.open("rb") as handle:
        for chunk in iter(lambda: handle.read(1024 * 1024), b""):
            digest.update(chunk)
    return digest.hexdigest()


def _next_layer_asset_id(base_id: str, existing_ids: set[str]) -> str:
    clean = str(base_id or "").strip() or "asset"
    candidate = clean
    counter = 2
    while candidate in existing_ids:
        candidate = f"{clean}_{counter}"
        counter += 1
    existing_ids.add(candidate)
    return candidate


def _merge_layer_studio_library_from_bundle(
    roots: TransferRoots,
    package_root: Path,
    backup_root: Path,
    file_progress: Callable[[Path], None] | None = None,
) -> tuple[dict[str, str], int, list[str]]:
    source_root = package_root / "LiveryLibrary" / layer_studio.LIBRARY_DIRNAME
    source_manifest = source_root / layer_studio.LIBRARY_FILE_NAME
    if not source_manifest.is_file():
        return {}, 0, []
    source_library = _read_json(source_manifest, {})
    if not isinstance(source_library, dict):
        return {}, 0, []

    target_root = _assert_import_target(roots, _layer_studio_library_root(roots), "transfer Layer Studio library merge target")
    target_manifest = target_root / layer_studio.LIBRARY_FILE_NAME
    backups = [_backup_target(target_manifest, backup_root, roots)]
    target_root.mkdir(parents=True, exist_ok=True)
    (target_root / layer_studio.LIBRARY_ASSETS_DIRNAME).mkdir(parents=True, exist_ok=True)

    target_library = layer_studio.load_asset_library(roots.livery_library)
    target_groups = [dict(row) for row in target_library.get("groups", []) if isinstance(row, dict)]
    target_assets = [dict(row) for row in target_library.get("assets", []) if isinstance(row, dict)]
    group_ids = {str(row.get("id") or "") for row in target_groups}
    for group in source_library.get("groups", []) if isinstance(source_library.get("groups"), list) else []:
        if not isinstance(group, dict):
            continue
        group_id = str(group.get("id") or "").strip()
        if not group_id or group_id in group_ids:
            continue
        target_groups.append(dict(group))
        group_ids.add(group_id)

    by_id = {str(row.get("id") or ""): row for row in target_assets if str(row.get("id") or "")}
    by_hash = {str(row.get("hash") or ""): row for row in target_assets if str(row.get("hash") or "")}
    existing_ids = set(by_id)
    mapping: dict[str, str] = {}
    copied = 0
    changed = False

    for asset in source_library.get("assets", []) if isinstance(source_library.get("assets"), list) else []:
        if not isinstance(asset, dict):
            continue
        old_id = str(asset.get("id") or "").strip()
        file_rel = str(asset.get("file") or "").strip()
        if not old_id or not file_rel:
            continue
        try:
            file_path = _safe_rel(file_rel)
        except ValueError:
            continue
        source_png = source_root / file_path
        if not source_png.is_file():
            continue
        asset_hash = str(asset.get("hash") or "").strip()
        if not asset_hash:
            asset_hash = f"sha256:{_sha256_file(source_png)}"

        existing = by_id.get(old_id)
        if existing and str(existing.get("hash") or "") == asset_hash:
            mapping[old_id] = old_id
            continue

        hash_match = by_hash.get(asset_hash)
        if hash_match:
            mapped_id = str(hash_match.get("id") or old_id)
            mapping[old_id] = mapped_id
            continue

        new_id = old_id if old_id not in existing_ids else _next_layer_asset_id(old_id, existing_ids)
        if new_id == old_id:
            existing_ids.add(new_id)
        target_name = f"{new_id}.png"
        target_rel = f"{layer_studio.LIBRARY_ASSETS_DIRNAME}/{target_name}"
        target_png = target_root / layer_studio.LIBRARY_ASSETS_DIRNAME / target_name
        package_zip.copy_file(source_png, target_png)
        if file_progress:
            file_progress(source_png)
        next_asset = dict(asset)
        next_asset.update({
            "id": new_id,
            "file": target_rel,
            "hash": asset_hash,
            "size": target_png.stat().st_size,
            "updatedAt": datetime.now().isoformat(timespec="seconds"),
        })
        target_assets.append(next_asset)
        by_id[new_id] = next_asset
        by_hash[asset_hash] = next_asset
        mapping[old_id] = new_id
        copied += 1
        changed = True

    if changed:
        layer_studio.save_asset_library(roots.livery_library, {
            "version": 1,
            "type": "layer-studio-asset-library",
            "groups": target_groups,
            "assets": target_assets,
        })
        copied += 1
    return mapping, copied, backups


def _rewrite_layer_studio_library_refs(project_root: Path, asset_mapping: dict[str, str]) -> int:
    if not asset_mapping:
        return 0
    layer_root = project_root / layer_studio.PROJECT_DIRNAME
    if not layer_root.exists():
        return 0
    changed_files = 0
    for layers_path in sorted(layer_root.rglob(layer_studio.LAYERS_FILE_NAME), key=lambda item: item.as_posix().lower()):
        document = _read_json(layers_path, {})
        if not isinstance(document, dict):
            continue
        changed = False
        for layer in _iter_layer_rows(document.get("layers")):
            if str(layer.get("sourceType") or "project").strip().lower() != "library":
                continue
            old_id = str(layer.get("source") or "").strip()
            new_id = asset_mapping.get(old_id)
            if new_id and new_id != old_id:
                layer["source"] = new_id
                changed = True
        if changed:
            _write_json(layers_path, document)
            changed_files += 1
    return changed_files


def _rewrite_imported_livery_preview_project(project_root: Path, entry: dict[str, Any]) -> bool:
    project_file = project_root / "preview_project.json"
    if not project_file.exists() or not project_file.is_file():
        return False
    data = _read_json(project_file, {})
    if not isinstance(data, dict):
        return False

    source_text = str(data.get("projectFolder") or "").strip()
    target_text = str(project_root)
    source_variants: set[str] = set()
    if source_text and Path(source_text).is_absolute():
        source_variants = {
            source_text,
            source_text.replace("\\", "/"),
            source_text.replace("/", "\\"),
        }

    def rewrite(value: Any) -> Any:
        if isinstance(value, dict):
            return {str(key): rewrite(item) for key, item in value.items()}
        if isinstance(value, list):
            return [rewrite(item) for item in value]
        if isinstance(value, str):
            next_value = value
            for source_variant in sorted(source_variants, key=len, reverse=True):
                if source_variant in next_value:
                    next_value = next_value.replace(source_variant, target_text)
            return next_value
        return value

    data = rewrite(data)

    def project_file_path(name: str) -> str:
        return str(project_root / name)

    def set_texture(filename: str, path_keys: tuple[str, ...], name_keys: tuple[str, ...], *, clear_missing: bool = False) -> None:
        path = project_root / filename
        if not path.is_file():
            if clear_missing:
                for key in path_keys:
                    data[key] = ""
                for key in name_keys:
                    data[key] = ""
            return
        for key in path_keys:
            data[key] = project_file_path(filename)
        for key in name_keys:
            data[key] = filename

    def set_texture_choice(filenames: tuple[str, ...], path_keys: tuple[str, ...], name_keys: tuple[str, ...], *, clear_missing: bool = False) -> None:
        for filename in filenames:
            if (project_root / filename).is_file():
                set_texture(filename, path_keys, name_keys)
                return
        if clear_missing:
            for key in path_keys:
                data[key] = ""
            for key in name_keys:
                data[key] = ""

    data["projectPath"] = str(project_file)
    data["projectFolder"] = target_text
    if str(entry.get("game_root") or "").strip():
        data["gameRoot"] = str(entry.get("game_root"))
    set_texture("EXT_SKIN_C.png", ("texturePath", "liveTexturePath"), ("textureName", "liveTextureName"))
    set_texture_choice(("EXT_Banner_C.png", "EXT_BANNER_C.png"), ("bannerTexturePath", "liveBannerTexturePath"), ("bannerTextureName", "liveBannerTextureName"), clear_missing=True)
    set_texture("EXT_Skin_D.png", ("detailTexturePath", "liveDetailTexturePath"), ("detailTextureName", "liveDetailTextureName"), clear_missing=True)
    data["skinKey"] = str(entry.get("key") or data.get("skinKey") or "")
    data["skinId"] = str(entry.get("skin_id") or data.get("skinId") or "")
    data["projectType"] = str(entry.get("project_type") or data.get("projectType") or "")
    data["displayName"] = str(entry.get("display_name") or data.get("displayName") or "")
    data["carModel"] = str(entry.get("car_model") or data.get("carModel") or "")
    data["updatedAt"] = datetime.now().isoformat(timespec="seconds")
    _write_json(project_file, data)
    return True


def overview(roots: TransferRoots) -> dict[str, Any]:
    skins = []
    skin_entries_for_categories: list[dict[str, Any]] = []
    for entry in _load_my_skins(roots):
        if not isinstance(entry, dict):
            continue
        key = str(entry.get("key") or "").strip()
        local_root = _skin_local_root(roots, entry)
        if not key or not local_root.exists():
            continue
        skin_entries_for_categories.append(entry)
        skins.append({
            "id": key,
            "label": str(entry.get("display_name") or entry.get("skin_id") or key),
            "carModel": str(entry.get("car_model") or ""),
            "path": str(local_root),
            "fileCount": _count_files(local_root),
            "bytes": _path_size(local_root),
            "selected": True,
        })
    custom_livery_categories = _my_livery_category_metadata(roots, skin_entries_for_categories)

    drivers = []
    for manifest_path in _driver_manifests(roots):
        manifest = _read_json(manifest_path, {})
        if not isinstance(manifest, dict):
            continue
        profile_id = str(manifest.get("id") or manifest_path.parent.name).strip()
        car_model = str(manifest.get("carModel") or manifest_path.parent.parent.name).strip()
        drivers.append({
            "id": f"{car_model}:{profile_id}",
            "profileId": profile_id,
            "label": str(manifest.get("name") or profile_id),
            "carModel": car_model,
            "path": str(manifest_path.parent),
            "fileCount": _count_files(manifest_path.parent),
            "bytes": _path_size(manifest_path.parent),
            "selected": True,
        })

    tyres = []
    for manifest_path in _tyre_manifests(roots):
        manifest = _read_json(manifest_path, {})
        if not isinstance(manifest, dict) or manifest.get("type") != "liverylab_custom_tyre_brand":
            continue
        brand_id = str(manifest.get("id") or manifest_path.parent.name).strip()
        tyres.append({
            "id": brand_id,
            "label": str(manifest.get("label") or manifest.get("brandName") or brand_id),
            "family": str(manifest.get("family") or ""),
            "path": str(manifest_path.parent),
            "fileCount": _count_files(manifest_path.parent),
            "bytes": _path_size(manifest_path.parent),
            "selected": True,
        })

    layer_studio_files = _layer_studio_file_count(roots)
    my_liveries_category = _category_overview("my_liveries", roots.livery_library / "LocalSkins", skins)
    my_liveries_category["liveryCategories"] = custom_livery_categories
    categories = [
        _category_overview("app_settings", roots.user_data / "settings.json"),
        my_liveries_category,
        _category_overview("driver_profiles", roots.livery_library / "Drivers", drivers),
        _category_overview("tyre_brands", roots.livery_library / "TyreBrands", tyres),
        _category_overview("custom_grids", roots.livery_library / "GridPresets"),
        _category_overview("numberplates", roots.livery_library / "Numberplates"),
        {
            "id": "layer_studio",
            "label": CATEGORY_LABELS["layer_studio"],
            "itemized": False,
            "selected": bool(layer_studio_files),
            "available": bool(layer_studio_files),
            "fileCount": layer_studio_files,
            "bytes": _layer_studio_size(roots),
            "items": [],
        },
    ]
    return {"type": BUNDLE_TYPE, "formatVersion": BUNDLE_VERSION, "categories": categories}


def _category_overview(category: str, path: Path, items: list[dict[str, Any]] | None = None) -> dict[str, Any]:
    item_rows = items or []
    itemized = category in ITEMIZED_CATEGORIES
    available = bool(item_rows) if itemized else path.exists()
    return {
        "id": category,
        "label": CATEGORY_LABELS[category],
        "itemized": itemized,
        "selected": available,
        "available": available,
        "fileCount": sum(int(item.get("fileCount") or 0) for item in item_rows) if itemized else _count_files(path),
        "bytes": sum(int(item.get("bytes") or 0) for item in item_rows) if itemized else _path_size(path),
        "items": item_rows,
    }


def _selected_item_ids(selection: dict[str, Any], category: str, all_ids: list[str]) -> set[str]:
    items = selection.get("items") if isinstance(selection.get("items"), dict) else {}
    raw = items.get(category)
    if raw is None:
        return set(all_ids)
    return {str(item) for item in raw if str(item).strip()}


def _category_selected(selection: dict[str, Any], category: str) -> bool:
    raw = selection.get("categories")
    if raw is None:
        return True
    return category in {str(item) for item in raw}


def _selected_export_file_total(roots: TransferRoots, selection: dict[str, Any]) -> int:
    total = 0
    for category in overview(roots).get("categories") or []:
        if not isinstance(category, dict):
            continue
        category_id = str(category.get("id") or "")
        if not category_id or not _category_selected(selection, category_id):
            continue
        if category_id in ITEMIZED_CATEGORIES:
            rows = category.get("items") if isinstance(category.get("items"), list) else []
            selected = _selected_item_ids(selection, category_id, [str(row.get("id") or "") for row in rows if isinstance(row, dict)])
            if category_id == "my_liveries":
                library_dependency_ids: set[str] = set()
                for entry in _load_my_skins(roots):
                    if not isinstance(entry, dict) or str(entry.get("key") or "") not in selected:
                        continue
                    local_root = _skin_local_root(roots, entry)
                    total += sum(
                        1 for path in _iter_files(local_root) or []
                        if not _exclude_non_portable_my_livery_path(path)
                    )
                    project_root = _livery_project_root(roots, entry)
                    try:
                        same_root = project_root.resolve() == local_root.resolve()
                    except Exception:
                        same_root = False
                    if project_root.exists() and not same_root:
                        total += sum(1 for _ in _iter_livery_project_files(project_root) or [])
                    library_dependency_ids.update(_layer_studio_library_refs_in_project(project_root))
                library = _read_json(_layer_studio_library_root(roots) / layer_studio.LIBRARY_FILE_NAME, {})
                assets = library.get("assets") if isinstance(library, dict) and isinstance(library.get("assets"), list) else []
                total += sum(
                    1 for asset in assets
                    if isinstance(asset, dict)
                    and str(asset.get("id") or "") in library_dependency_ids
                    and (_layer_studio_library_root(roots) / str(asset.get("file") or "")).is_file()
                )
                continue
            total += sum(int(row.get("fileCount") or 0) for row in rows if isinstance(row, dict) and str(row.get("id") or "") in selected)
            continue
        total += int(category.get("fileCount") or 0)
    return total


def _selection_with_required_dependencies(roots: TransferRoots, selection: dict[str, Any]) -> tuple[dict[str, Any], list[dict[str, Any]]]:
    data = {
        "categories": [str(item) for item in selection.get("categories") or [] if str(item).strip()],
        "items": {
            str(category): [str(item) for item in rows if str(item).strip()]
            for category, rows in (selection.get("items") or {}).items()
            if isinstance(rows, list)
        },
    }
    if not data["categories"]:
        data["categories"] = list(EXPORT_CATEGORY_IDS)

    category_set = set(data["categories"])
    overview_rows = {
        str(category.get("id") or ""): category
        for category in overview(roots).get("categories") or []
        if isinstance(category, dict)
    }
    tyre_rows = {
        str(row.get("id") or "").lower(): row
        for row in overview_rows.get("tyre_brands", {}).get("items", []) or []
        if isinstance(row, dict)
    }
    driver_rows = {
        str(row.get("id") or "").lower(): row
        for row in overview_rows.get("driver_profiles", {}).get("items", []) or []
        if isinstance(row, dict)
    }
    selected_skin_ids = _selected_item_ids(
        data,
        "my_liveries",
        [str(entry.get("key") or "") for entry in _load_my_skins(roots) if isinstance(entry, dict)],
    )
    if "my_liveries" not in category_set:
        return data, []

    dependencies: list[dict[str, Any]] = []

    def add_item(category: str, item_id: str, item_row: dict[str, Any], skin: dict[str, Any]) -> None:
        if not item_id:
            return
        already_selected = category in category_set and category not in data["items"]
        if category not in category_set or category in data["items"]:
            rows = data["items"].setdefault(category, [])
            selected_lower = {str(item).lower() for item in rows}
            already_selected = item_id.lower() in selected_lower
            if not already_selected:
                rows.append(item_id)
        category_set.add(category)
        data["categories"] = [item for item in EXPORT_CATEGORY_IDS if item in category_set]
        if already_selected:
            return
        dependency_key = f"{category}:{item_id.lower()}"
        existing = next((row for row in dependencies if row.get("_key") == dependency_key), None)
        required_by = str(skin.get("display_name") or skin.get("skin_id") or skin.get("key") or "").strip()
        if existing:
            if required_by and required_by not in existing["requiredBy"]:
                existing["requiredBy"].append(required_by)
            return
        dependencies.append({
            "_key": dependency_key,
            "category": category,
            "id": item_id,
            "label": str(item_row.get("label") or item_id),
            "requiredBy": [required_by] if required_by else [],
        })

    for skin in _load_my_skins(roots):
        if not isinstance(skin, dict) or str(skin.get("key") or "") not in selected_skin_ids:
            continue
        tyre_brand = skin.get("tyre_brand") if isinstance(skin.get("tyre_brand"), dict) else {}
        tyre_id = str(tyre_brand.get("selection") or tyre_brand.get("brand") or tyre_brand.get("id") or "").strip()
        if tyre_id and tyre_id.lower() not in {"default", "from_car", "car", "custom"}:
            tyre_row = tyre_rows.get(tyre_id.lower())
            if tyre_row:
                add_item("tyre_brands", str(tyre_row.get("id") or tyre_id), tyre_row, skin)

        driver_profile = skin.get("driver_profile") if isinstance(skin.get("driver_profile"), dict) else {}
        driver_selection = str(driver_profile.get("selection") or "").strip().lower()
        driver_profile_id = str(driver_profile.get("profileId") or driver_profile.get("id") or "").strip()
        driver_car = str(driver_profile.get("carModel") or skin.get("car_model") or "").strip()
        if driver_selection == "profile" and driver_profile_id and driver_car:
            driver_key = f"{driver_car}:{driver_profile_id}"
            driver_row = driver_rows.get(driver_key.lower())
            if driver_row:
                add_item("driver_profiles", str(driver_row.get("id") or driver_key), driver_row, skin)

    for row in dependencies:
        row.pop("_key", None)
    return data, dependencies


def export_bundle(roots: TransferRoots, target_dir: str | Path, selection: dict[str, Any], app_version: str, progress: ProgressCallback | None = None) -> dict[str, Any]:
    roots.temp.mkdir(parents=True, exist_ok=True)
    target_base = Path(target_dir).expanduser()
    if target_base.suffix.lower() == ".zip":
        zip_path = target_base
        zip_path.parent.mkdir(parents=True, exist_ok=True)
    else:
        target_base.mkdir(parents=True, exist_ok=True)
        zip_path = target_base / f"LLT_{_short_bundle_stamp()}.zip"
        index = 1
        while zip_path.exists():
            index += 1
            zip_path = target_base / f"LLT_{_short_bundle_stamp()}_{index}.zip"

    expanded_selection, required_dependencies = _selection_with_required_dependencies(roots, selection)
    categories: list[dict[str, Any]] = []
    total_files = _selected_export_file_total(roots, expanded_selection)
    progress_state = {"processed": 0}

    def emit_progress(**payload: Any) -> None:
        processed = int(progress_state.get("processed") or 0)
        data = {
            "totalFiles": total_files,
            "processedFiles": processed,
            **payload,
        }
        if "percent" not in data:
            data["percent"] = round((processed / total_files) * 100) if total_files > 0 else 0
        _emit(progress, data)

    def mark_file(category: str, file_path: Path) -> None:
        progress_state["processed"] += 1
        processed = int(progress_state["processed"])
        label = CATEGORY_LABELS.get(category, category)
        emit_progress(
            phase="copy",
            category=category,
            label=label,
            path=str(file_path),
            message=f"{processed} / {total_files} files",
        )

    emit_progress(phase="start", message="Preparing transfer ZIP...", path=str(zip_path))
    with tempfile.TemporaryDirectory(prefix="t_", dir=str(roots.temp)) as tmp_text:
        tmp = Path(tmp_text)
        bundle_root = tmp / "bundle"
        bundle_root.mkdir(parents=True, exist_ok=True)
        for category in EXPORT_CATEGORY_IDS:
            if not _category_selected(expanded_selection, category):
                continue
            emit_progress(phase="category_start", category=category, label=CATEGORY_LABELS.get(category, category), message="Collecting files...")
            package = _export_category(category, roots, tmp, bundle_root, expanded_selection, mark_file, emit_progress)
            if package:
                categories.append(package)

        for json_path in sorted(bundle_root.rglob("*.json"), key=lambda item: item.as_posix().lower()):
            export_sanitize.rewrite_json_file_for_archive(json_path, portable_paths=True)

        manifest = {
            "type": BUNDLE_TYPE,
            "formatVersion": BUNDLE_VERSION,
            "app": {"name": "LiveryLab", "version": app_version},
            "createdAt": datetime.now().isoformat(timespec="seconds"),
            "categories": categories,
            "requiredDependencies": required_dependencies,
            "requiredDependencyCount": len(required_dependencies),
        }
        _write_json(bundle_root / BUNDLE_MANIFEST, manifest)
        emit_progress(phase="zip", percent=99, message="Packing transfer ZIP...", path=str(zip_path))
        package_zip.zip_directory(bundle_root, zip_path)
    emit_progress(phase="done", percent=100, message="Transfer export complete.", path=str(zip_path))
    return {
        "bundleRoot": str(zip_path),
        "bundlePath": str(zip_path),
        "manifestPath": BUNDLE_MANIFEST,
        "categories": categories,
        "packages": categories,
        "categoryCount": len(categories),
        "packageCount": 1 if categories else 0,
        "requiredDependencies": required_dependencies,
        "requiredDependencyCount": len(required_dependencies),
    }


def _write_category_package(stage: Path, bundle_root: Path, category: str, items: list[dict[str, Any]], file_count: int, emit_progress: Callable[..., None] | None = None) -> dict[str, Any] | None:
    if file_count <= 0 and category != "app_settings":
        return None
    if emit_progress:
        emit_progress(phase="category_done", category=category, label=CATEGORY_LABELS[category], path=str(bundle_root), message="Category ready.")
    return {
        "kind": category,
        "category": category,
        "label": CATEGORY_LABELS[category],
        "path": "",
        "itemCount": len(items),
        "fileCount": file_count,
        "items": items,
    }


def _scope_for_transfer_key(key: str) -> str:
    clean = str(key or "").strip().lower()
    if clean.startswith("official_external_") or clean.startswith("official_external:"):
        return workflow_scopes.SCOPE_OFFICIAL
    return workflow_scopes.SCOPE_ADVANCED


def _my_livery_category_metadata(roots: TransferRoots, exported_entries: list[dict[str, Any]]) -> list[dict[str, Any]]:
    entries = [entry for entry in exported_entries if isinstance(entry, dict) and str(entry.get("key") or "").strip()]
    if not entries:
        return []
    settings = _read_json(roots.user_data / "settings.json", {})
    if not isinstance(settings, dict):
        settings = {}
    metadata: list[dict[str, Any]] = []
    for scope in (workflow_scopes.SCOPE_ADVANCED, workflow_scopes.SCOPE_OFFICIAL):
        scoped_keys = [
            str(entry.get("key") or "").strip()
            for entry in entries
            if workflow_scopes.scope_for_entry(entry) == scope
        ]
        if not scoped_keys:
            continue
        state = livery_categories.load_state(settings, scoped_keys, scope)
        assignments = state.get("assignments") if isinstance(state.get("assignments"), dict) else {}
        assignments_by_lookup = {
            str(skin_key or "").strip().lower(): str(category_id or "").strip()
            for skin_key, category_id in assignments.items()
        }
        categories = state.get("categories") if isinstance(state.get("categories"), list) else []
        for category in categories:
            if not isinstance(category, dict):
                continue
            category_id = str(category.get("id") or "").strip()
            name = str(category.get("name") or "").strip()
            if not category_id or not name:
                continue
            item_ids = [
                key
                for key in scoped_keys
                if assignments_by_lookup.get(key.lower()) == category_id
            ]
            if not item_ids:
                continue
            metadata.append({
                "id": category_id,
                "name": name,
                "scope": scope,
                "sortMode": state.get("sortMode") or livery_categories.SORT_CREATED,
                "itemIds": item_ids,
                "itemCount": len(item_ids),
            })
    return metadata


def _restore_my_livery_category_metadata(
    roots: TransferRoots,
    manifest: dict[str, Any],
    imported_keys: list[str],
    all_skin_keys: list[str],
) -> dict[str, int]:
    rows = manifest.get("liveryCategories")
    if not isinstance(rows, list) or not rows:
        return {"categories": 0, "assignments": 0}
    imported_by_lookup = {
        str(key or "").strip().lower(): str(key or "").strip()
        for key in imported_keys
        if str(key or "").strip()
    }
    if not imported_by_lookup:
        return {"categories": 0, "assignments": 0}

    settings_path = _assert_import_target(roots, roots.user_data / "settings.json", "transfer livery category settings target")
    settings = _read_json(settings_path, {})
    if not isinstance(settings, dict):
        settings = {}

    def save_settings(data: dict[str, Any]) -> Path:
        _write_json(settings_path, data)
        return settings_path

    restored_categories = 0
    restored_assignments = 0
    for row in rows:
        if not isinstance(row, dict):
            continue
        name = str(row.get("name") or "").strip()
        if not name:
            continue
        raw_item_ids = row.get("itemIds") if isinstance(row.get("itemIds"), list) else []
        item_ids = []
        for raw_item_id in raw_item_ids:
            imported_key = imported_by_lookup.get(str(raw_item_id or "").strip().lower())
            if imported_key:
                item_ids.append(imported_key)
        if not item_ids:
            continue

        scope = workflow_scopes.normalize_scope(row.get("scope"), default=workflow_scopes.SCOPE_ALL)
        if scope == workflow_scopes.SCOPE_ALL:
            scope_counts: dict[str, int] = {}
            for item_id in item_ids:
                item_scope = _scope_for_transfer_key(item_id)
                scope_counts[item_scope] = scope_counts.get(item_scope, 0) + 1
            scope = max(scope_counts, key=scope_counts.get) if scope_counts else workflow_scopes.SCOPE_ADVANCED
        scoped_all_skin_keys = [key for key in all_skin_keys if _scope_for_transfer_key(key) == scope]
        state = livery_categories.load_state(settings, scoped_all_skin_keys, scope)
        categories = state.get("categories") if isinstance(state.get("categories"), list) else []
        category_id = ""
        for category in categories:
            if isinstance(category, dict) and str(category.get("name") or "").strip().lower() == name.lower():
                category_id = str(category.get("id") or "").strip()
                break
        if not category_id:
            created_state = livery_categories.create_category(settings, save_settings, name, scoped_all_skin_keys, scope)
            category = created_state.get("category") if isinstance(created_state.get("category"), dict) else {}
            category_id = str(category.get("id") or "").strip()
            restored_categories += 1
        if not category_id:
            continue

        state = livery_categories.load_state(settings, scoped_all_skin_keys, scope)
        assignments = dict(state.get("assignments") if isinstance(state.get("assignments"), dict) else {})
        for item_id in item_ids:
            if assignments.get(item_id) == category_id:
                continue
            assignments[item_id] = category_id
            restored_assignments += 1
        livery_categories.save_state(settings, save_settings, state.get("categories", []), assignments, scoped_all_skin_keys, scope, state.get("sortMode", livery_categories.SORT_CREATED))
    return {"categories": restored_categories, "assignments": restored_assignments}


def _export_category(
    category: str,
    roots: TransferRoots,
    tmp: Path,
    bundle_root: Path,
    selection: dict[str, Any],
    mark_file: Callable[[str, Path], None] | None = None,
    emit_progress: Callable[..., None] | None = None,
) -> dict[str, Any] | None:
    stage = bundle_root
    stage.mkdir(parents=True, exist_ok=True)
    items: list[dict[str, Any]] = []
    file_count = 0

    if category == "app_settings":
        source = roots.user_data / "settings.json"
        if not source.exists():
            return None
        file_count += _copy_any(source, stage / "UserData" / "settings.json", lambda path: mark_file(category, path) if mark_file else None)
        items.append({"id": "settings", "label": "settings.json"})
    elif category == "my_liveries":
        skins = [entry for entry in _load_my_skins(roots) if isinstance(entry, dict)]
        selected = _selected_item_ids(selection, category, [str(entry.get("key") or "") for entry in skins])
        selected_entries = [entry for entry in skins if str(entry.get("key") or "") in selected]
        exported_entries: list[dict[str, Any]] = []
        library_dependency_ids: set[str] = set()
        for entry in selected_entries:
            entry = dict(entry)
            local_root = _skin_local_root(roots, entry)
            if not local_root.exists():
                continue
            rel = _relative_to_roots(local_root, roots)
            if rel is None:
                continue
            staged_local_root = stage / rel
            file_count += _copy_any(
                local_root,
                staged_local_root,
                lambda path: mark_file(category, path) if mark_file else None,
                exclude=_exclude_non_portable_my_livery_path,
            )
            file_count += _hydrate_my_livery_game_files(roots, entry, staged_local_root)
            project_file_count = 0
            project_root = _livery_project_root(roots, entry)
            try:
                project_is_local_root = project_root.resolve() == local_root.resolve()
            except Exception:
                project_is_local_root = False
            if project_root.exists() and not project_is_local_root:
                for file_path in _iter_livery_project_files(project_root) or []:
                    project_rel = _relative_to_roots(file_path, roots)
                    if project_rel is None:
                        continue
                    file_count += _copy_any(file_path, stage / project_rel, lambda path: mark_file(category, path) if mark_file else None)
                    project_file_count += 1
            if project_root.exists():
                library_dependency_ids.update(_layer_studio_library_refs_in_project(project_root))
            entry = _strip_generated_thumbnail_metadata(entry)
            entry, optional_missing = _sanitize_optional_thumbnail_refs(entry, staged_local_root)
            entry = export_sanitize.clean_my_skin_entry(entry, portable_paths=True)
            _strip_disabled_numberplate_metadata_file(staged_local_root / "liverylab_skin.json")
            mandatory_missing = _mandatory_transfer_missing_files(entry, staged_local_root)
            if mandatory_missing:
                if project_types.project_type_for_entry(entry) == project_types.PROJECT_TYPE_OFFICIAL_EXTERNAL_LIVERY:
                    missing_rows = ", ".join(str(row.get("path") or "") for row in mandatory_missing)
                    raise FileNotFoundError(f"Official project transfer is missing required files: {missing_rows}")
                entry["transfer_missing_required_files"] = mandatory_missing
            exported_entries.append(entry)
            item = {"id": entry.get("key") or "", "label": entry.get("display_name") or entry.get("skin_id") or "", "path": _norm_rel(rel)}
            if project_file_count:
                item["projectFileCount"] = project_file_count
            if optional_missing:
                item["missingOptionalCount"] = len(optional_missing)
            if mandatory_missing:
                item["missingRequiredCount"] = len(mandatory_missing)
            items.append(item)
        dependency_count = _write_layer_studio_library_subset(
            roots,
            stage,
            library_dependency_ids,
            mark_file=mark_file,
            category=category,
        )
        if dependency_count:
            file_count += dependency_count
            items.append({"id": "layer_studio_library_dependencies", "label": "Layer Studio PNG dependencies", "fileCount": dependency_count})
        if exported_entries:
            _write_json(stage / "LiveryLibrary" / "my_skins.json", _my_skins_registry_payload(exported_entries))
            file_count += 1
    elif category == "driver_profiles":
        rows = overview(roots)["categories"][2]["items"]
        selected = _selected_item_ids(selection, category, [row["id"] for row in rows])
        for row in rows:
            if row["id"] not in selected:
                continue
            source = Path(row["path"])
            rel = _relative_to_roots(source, roots)
            if rel is None:
                continue
            staged_profile = stage / rel
            file_count += _copy_any(source, staged_profile, lambda path: mark_file(category, path) if mark_file else None)
            export_sanitize.rewrite_json_file_for_archive(staged_profile / "manifest.json", portable_paths=True)
            project = roots.livery_projects / "Drivers" / str(row["carModel"]) / str(row["profileId"])
            if project.exists():
                project_rel = _relative_to_roots(project, roots)
                if project_rel:
                    staged_project = stage / project_rel
                    file_count += _copy_any(project, staged_project, lambda path: mark_file(category, path) if mark_file else None)
                    export_sanitize.rewrite_json_file_for_archive(staged_project / "driver_project.json", portable_paths=True)
            item = {"id": row["id"], "label": row["label"], "path": _norm_rel(rel)}
            if project.exists() and project_rel:
                item["projectPath"] = _norm_rel(project_rel)
                item["projectFileCount"] = _count_files(project)
            items.append(item)
    elif category == "tyre_brands":
        rows = overview(roots)["categories"][3]["items"]
        selected = _selected_item_ids(selection, category, [row["id"] for row in rows])
        for row in rows:
            if row["id"] not in selected:
                continue
            source = Path(row["path"])
            rel = _relative_to_roots(source, roots)
            if rel is None:
                continue
            file_count += _copy_any(source, stage / rel, lambda path: mark_file(category, path) if mark_file else None)
            items.append({"id": row["id"], "label": row["label"], "path": _norm_rel(rel)})
    elif category == "custom_grids":
        source = roots.livery_library / "GridPresets"
        if source.exists():
            file_count += _copy_any(source, stage / "LiveryLibrary" / "GridPresets", lambda path: mark_file(category, path) if mark_file else None)
            export_sanitize.rewrite_json_file_for_archive(stage / "LiveryLibrary" / "GridPresets" / "grid_presets.json", portable_paths=True)
            items.append({"id": "grid_presets", "label": "GridPresets"})
    elif category == "numberplates":
        source = roots.livery_library / "Numberplates"
        if source.exists():
            file_count += _copy_any(source, stage / "LiveryLibrary" / "Numberplates", lambda path: mark_file(category, path) if mark_file else None)
            items.append({"id": "numberplates", "label": "Numberplates"})
    elif category == "layer_studio":
        library_root = _layer_studio_library_root(roots)
        if library_root.exists():
            rel = _relative_to_roots(library_root, roots)
            if rel is not None:
                file_count += _copy_any(library_root, stage / rel, lambda path: mark_file(category, path) if mark_file else None)
                items.append({"id": "layer_studio_library", "label": "PNG Library", "path": _norm_rel(rel)})
    elif category == "project_files":
        for file_path in _project_allowed_files(roots):
            rel = _relative_to_roots(file_path, roots)
            if rel is None:
                continue
            file_count += _copy_any(file_path, stage / rel, lambda path: mark_file(category, path) if mark_file else None)
        if file_count:
            items.append({"id": "project_files", "label": "LiveryLab-managed project files"})
    package = _write_category_package(stage, bundle_root, category, items, file_count, emit_progress)
    if package and category == "my_liveries":
        metadata = _my_livery_category_metadata(roots, exported_entries)
        if metadata:
            package["liveryCategories"] = metadata
            package["liveryCategoryCount"] = len(metadata)
    return package


def inspect_bundle(roots: TransferRoots, bundle_dir: str | Path) -> dict[str, Any]:
    roots.temp.mkdir(parents=True, exist_ok=True)
    bundle_path = Path(bundle_dir).expanduser().resolve()
    if bundle_path.suffix.lower() != ".zip":
        raise ValueError("Transfer bundle must be a v2 .zip file")
    with package_zip.package_root(
        bundle_path,
        roots.temp,
        allow_folder=False,
        required_manifest=BUNDLE_MANIFEST,
        **_transfer_zip_options(),
    ) as bundle_root:
        package_security.validate_package_root_structure(
            bundle_root,
            allowed_top_level=TRANSFER_TOP_LEVEL,
            required_files={BUNDLE_MANIFEST},
            label="Transfer bundle",
        )
        manifest_path = bundle_root / BUNDLE_MANIFEST
        manifest = _read_json(manifest_path, {})
        if not isinstance(manifest, dict) or manifest.get("type") != BUNDLE_TYPE:
            raise ValueError("Selected ZIP is not a LiveryLab transfer bundle")
        if int(manifest.get("formatVersion") or 0) != BUNDLE_VERSION:
            raise ValueError(f"Unsupported transfer bundle version: {manifest.get('formatVersion')}")
        categories = []
        for row in manifest.get("categories") or []:
            if not isinstance(row, dict):
                continue
            kind = str(row.get("kind") or row.get("category") or "")
            if kind not in EXPORT_CATEGORY_IDS:
                continue
            categories.append({
                **row,
                "kind": kind,
                "category": kind,
                "label": str(row.get("label") or CATEGORY_LABELS[kind]),
                "items": row.get("items") if isinstance(row.get("items"), list) else [],
                "itemCount": int(row.get("itemCount") or 0),
                "fileCount": int(row.get("fileCount") or 0),
                "selected": True,
            })
    return {
        "bundleRoot": str(bundle_path),
        "bundlePath": str(bundle_path),
        "manifestPath": BUNDLE_MANIFEST,
        "manifest": manifest,
        "categories": categories,
        "packages": categories,
        "categoryCount": len(categories),
        "packageCount": 1 if categories else 0,
        "missing": [],
        "missingCount": 0,
        "requiredDependencies": manifest.get("requiredDependencies") if isinstance(manifest.get("requiredDependencies"), list) else [],
        "requiredDependencyCount": int(manifest.get("requiredDependencyCount") or 0),
    }


def import_bundle(roots: TransferRoots, bundle_dir: str | Path, categories: list[str] | None = None, progress: ProgressCallback | None = None) -> dict[str, Any]:
    info = inspect_bundle(roots, bundle_dir)
    selected = {str(item) for item in (categories or []) if str(item).strip()}
    if not selected:
        selected = {str(row.get("kind") or "") for row in info.get("categories") or []}
    selected_rows = [
        row for row in info.get("categories") or []
        if isinstance(row, dict) and str(row.get("kind") or "") in selected and str(row.get("kind") or "") in EXPORT_CATEGORY_IDS
    ]
    total_files = sum(int(row.get("fileCount") or 0) for row in selected_rows)
    processed_files = 0

    def emit_progress(**payload: Any) -> None:
        _emit(progress, payload)

    def mark_file(category: str, path: Path) -> None:
        nonlocal processed_files
        processed_files += 1
        emit_progress(
            phase="file",
            category=category,
            label=CATEGORY_LABELS.get(category, category),
            processedFiles=processed_files,
            totalFiles=total_files,
            currentFile=str(path),
            message="Importing files...",
        )

    emit_progress(phase="start", percent=0, processedFiles=0, totalFiles=total_files, message="Preparing transfer import...", path=str(info.get("bundlePath") or bundle_dir))
    backup_root = roots.user_data / "transfer_import_backups" / _now_stamp()
    imported = []
    with package_zip.package_root(
        info.get("bundlePath") or bundle_dir,
        roots.temp,
        allow_folder=False,
        required_manifest=BUNDLE_MANIFEST,
        **_transfer_zip_options(),
    ) as package_root:
        package_security.validate_package_root_structure(
            package_root,
            allowed_top_level=TRANSFER_TOP_LEVEL,
            required_files={BUNDLE_MANIFEST},
            label="Transfer bundle",
        )
        for row in selected_rows:
            kind = str(row.get("kind") or "")
            emit_progress(
                phase="category_start",
                category=kind,
                label=CATEGORY_LABELS.get(kind, kind),
                processedFiles=processed_files,
                totalFiles=total_files,
                message="Starting category import...",
            )
            imported.append(_import_category(roots, package_root, backup_root, row, mark_file=mark_file))
            emit_progress(
                phase="category_done",
                category=kind,
                label=CATEGORY_LABELS.get(kind, kind),
                processedFiles=processed_files,
                totalFiles=total_files,
                message="Category imported.",
            )
    if not backup_root.exists():
        backup_root.mkdir(parents=True, exist_ok=True)
    _write_json(backup_root / "import_manifest.json", {"source": info.get("bundlePath"), "imported": imported})
    emit_progress(phase="done", percent=100, processedFiles=processed_files, totalFiles=total_files, message="Transfer import complete.", path=str(backup_root))
    return {
        "bundleRoot": info.get("bundlePath"),
        "bundlePath": info.get("bundlePath"),
        "imported": imported,
        "importedCount": len(imported),
        "backupFolder": str(backup_root),
    }


def _import_category(roots: TransferRoots, package_root: Path, backup_root: Path, manifest: dict[str, Any], mark_file: Callable[[str, Path], None] | None = None) -> dict[str, Any]:
    category = str(manifest.get("category") or manifest.get("kind") or "")
    if category not in CATEGORY_LABELS:
        raise ValueError(f"Unsupported transfer category: {category}")
    file_progress = (lambda path: mark_file(category, path)) if mark_file else None
    if category == "app_settings":
        return _import_app_settings(roots, package_root, backup_root, manifest, file_progress=file_progress)
    if category == "my_liveries":
        return _import_my_liveries(roots, package_root, backup_root, manifest, file_progress=file_progress)
    if category == "driver_profiles":
        return _import_driver_profiles(roots, package_root, backup_root, manifest, file_progress=file_progress)
    if category == "tyre_brands":
        return _import_tree_items(roots, package_root, backup_root, manifest, "LiveryLibrary/TyreBrands", file_progress=file_progress)
    if category == "custom_grids":
        return _import_replace_root(roots, package_root, backup_root, manifest, roots.livery_library / "GridPresets", "LiveryLibrary/GridPresets", file_progress=file_progress)
    if category == "numberplates":
        return _import_replace_root(roots, package_root, backup_root, manifest, roots.livery_library / "Numberplates", "LiveryLibrary/Numberplates", file_progress=file_progress)
    if category == "layer_studio":
        return _import_layer_studio(roots, package_root, backup_root, manifest, file_progress=file_progress)
    if category == "project_files":
        return _import_project_files(roots, package_root, backup_root, manifest, file_progress=file_progress)
    raise ValueError(f"Unsupported transfer category: {category}")


def _import_app_settings(roots: TransferRoots, package_root: Path, backup_root: Path, manifest: dict[str, Any], file_progress: Callable[[Path], None] | None = None) -> dict[str, Any]:
    source = package_root / "UserData" / "settings.json"
    target = _assert_import_target(roots, roots.user_data / "settings.json", "transfer settings import target")
    backups = [_backup_target(target, backup_root, roots)]
    copied = 0
    if source.exists():
        incoming = _read_json(source, {})
        current = _read_json(target, {})
        if not isinstance(incoming, dict):
            incoming = {}
        if not isinstance(current, dict):
            current = {}
        source_game_root = str(incoming.get("default_root_folder") or "").strip()
        incoming = _rebase_source_game_paths(incoming, source_game_root, roots.game_root)
        portable = {
            key: value
            for key, value in incoming.items()
            if key not in MACHINE_LOCAL_SETTING_KEYS and not key.startswith("local_storage_cleanup_")
        }
        merged = {**current, **portable}
        _write_json(target, merged)
        copied = 1
        if file_progress:
            file_progress(source)
    return _import_result(manifest, copied, backups)


def _import_my_liveries(roots: TransferRoots, package_root: Path, backup_root: Path, manifest: dict[str, Any], file_progress: Callable[[Path], None] | None = None) -> dict[str, Any]:
    source_registry = package_root / "LiveryLibrary" / "my_skins.json"
    entries = _coerce_my_skins(_read_json(source_registry, {}))
    backups = [_backup_target(_skin_registry_path(roots), backup_root, roots)]
    copied = 0
    asset_mapping, library_copied, library_backups = _merge_layer_studio_library_from_bundle(roots, package_root, backup_root, file_progress)
    copied += library_copied
    backups.extend(library_backups)
    imported_entries: list[dict[str, Any]] = []
    imported_projects: list[tuple[Path, dict[str, Any]]] = []
    item_paths = {
        str(row.get("id") or "").strip().lower(): str(row.get("path") or "").strip()
        for row in manifest.get("items") or []
        if isinstance(row, dict) and str(row.get("id") or "").strip()
    }
    for entry in entries:
        if not isinstance(entry, dict):
            continue
        entry = _strip_disabled_numberplate_metadata(_strip_generated_thumbnail_metadata(entry))
        official_role = _official_transfer_role(entry)
        official_project = official_role == official_external_workflow.ROLE_PROJECT
        official_library = bool(official_role and not official_project)
        item_rel_text = item_paths.get(str(entry.get("key") or "").strip().lower(), "")
        item_rel = _safe_rel(item_rel_text) if item_rel_text else None
        expected_root = "OfficialLiveryProjects" if official_project else ("OfficialLiveryLibrary" if official_library else "LiveryLibrary")
        if item_rel is not None and item_rel.parts and item_rel.parts[0] == expected_root:
            local_rel = item_rel
        elif official_project:
            local_rel = Path("OfficialLiveryProjects") / str(entry.get("car_model") or "car") / str(entry.get("skin_id") or "skin")
        elif official_library:
            local_rel = Path("OfficialLiveryLibrary") / str(entry.get("car_model") or "car") / str(entry.get("skin_id") or "skin")
        else:
            local_rel = Path("LiveryLibrary") / "LocalSkins" / str(entry.get("car_model") or "car") / str(entry.get("skin_id") or "skin")
        source = package_root / local_rel
        target = _target_for_rooted_rel(roots, local_rel, "transfer My Liveries import target")
        backups.append(_backup_target(target, backup_root, roots))
        copied += _copy_any(source, target, file_progress, exclude=_exclude_non_portable_my_livery_path)
        _rewrite_imported_json_paths(target, roots)
        _strip_disabled_numberplate_metadata_file(target / "liverylab_skin.json")
        project_rel = local_rel if official_project else Path("LiveryProjects") / str(entry.get("car_model") or "car") / str(entry.get("skin_id") or "skin")
        source_project = package_root / project_rel
        target_project = _assert_import_target(
            roots,
            target if official_project else roots.livery_projects / str(entry.get("car_model") or "car") / str(entry.get("skin_id") or "skin"),
            "transfer My Liveries project import target",
        )
        if source_project.exists() and not official_library:
            for source_file in source_project.rglob("*"):
                if not source_file.is_file() or not _livery_project_file_allowed(source_file):
                    continue
                rel = source_file.relative_to(source_project)
                target_file = target_project / rel
                backups.append(_backup_target(target_file, backup_root, roots))
                copied += _copy_any(source_file, target_file, file_progress)
            _rewrite_imported_json_paths(target_project, roots)
        entry = _reset_transferred_entry_state(entry, target, roots)
        if source_project.exists() and not official_library:
            imported_projects.append((target_project, entry))
        _rewrite_imported_skin_metadata(target, entry)
        if official_project:
            _reset_imported_official_project_metadata(target, roots)
        imported_entries.append(entry)
    for project_root, entry in imported_projects:
        _rewrite_layer_studio_library_refs(project_root, asset_mapping)
        if _rewrite_imported_livery_preview_project(project_root, entry):
            copied += 1
    current = [row for row in _load_my_skins(roots) if isinstance(row, dict)]
    keys = {str(entry.get("key") or "").lower() for entry in imported_entries if isinstance(entry, dict)}
    merged = [row for row in current if str(row.get("key") or "").lower() not in keys]
    merged.extend(imported_entries)
    _write_json(_assert_import_target(roots, _skin_registry_path(roots), "transfer My Liveries registry target"), _my_skins_registry_payload(merged))
    copied += 1
    if isinstance(manifest.get("liveryCategories"), list) and manifest.get("liveryCategories"):
        backups.append(_backup_target(roots.user_data / "settings.json", backup_root, roots))
    category_restore = _restore_my_livery_category_metadata(
        roots,
        manifest,
        [str(entry.get("key") or "") for entry in imported_entries if isinstance(entry, dict)],
        [str(entry.get("key") or "") for entry in merged if isinstance(entry, dict)],
    )
    if category_restore["categories"] or category_restore["assignments"]:
        copied += 1
    result = _import_result(manifest, copied, backups)
    if category_restore["categories"] or category_restore["assignments"]:
        result["liveryCategoriesImported"] = category_restore["categories"]
        result["liveryCategoryAssignmentsImported"] = category_restore["assignments"]
    return result


def _import_tree_items(roots: TransferRoots, package_root: Path, backup_root: Path, manifest: dict[str, Any], allowed_prefix: str, rewrite_drivers: bool = False, file_progress: Callable[[Path], None] | None = None) -> dict[str, Any]:
    backups: list[str] = []
    copied = 0
    prefix_parts = _safe_rel(allowed_prefix).parts
    for item in manifest.get("items") or []:
        if not isinstance(item, dict):
            continue
        rel = str(item.get("path") or "").strip()
        rel_path = _safe_rel(rel)
        if rel_path.parts[: len(prefix_parts)] != prefix_parts:
            continue
        source = package_root / rel_path
        target = _target_for_rooted_rel(roots, rel_path, "transfer tree import target")
        backups.append(_backup_target(target, backup_root, roots))
        copied += _copy_any(source, target, file_progress)
        _rewrite_imported_json_paths(target, roots)
        if rewrite_drivers:
            _rewrite_driver_transfer_paths(target, roots)
    return _import_result(manifest, copied, backups)


def _driver_project_rel_for_profile_item(item: dict[str, Any], profile_rel_path: Path) -> Path | None:
    project_rel = str(item.get("projectPath") or "").strip()
    if project_rel:
        rel_path = _safe_rel(project_rel)
        if rel_path.parts[:2] == ("LiveryProjects", "Drivers"):
            return rel_path

    parts = profile_rel_path.parts
    if len(parts) >= 4 and parts[0] == "LiveryLibrary" and parts[1] == "Drivers":
        return Path("LiveryProjects") / "Drivers" / parts[2] / parts[3]
    return None


def _import_driver_profiles(
    roots: TransferRoots,
    package_root: Path,
    backup_root: Path,
    manifest: dict[str, Any],
    file_progress: Callable[[Path], None] | None = None,
) -> dict[str, Any]:
    backups: list[str] = []
    copied = 0
    profile_prefix = _safe_rel("LiveryLibrary/Drivers").parts

    for item in manifest.get("items") or []:
        if not isinstance(item, dict):
            continue
        rel = str(item.get("path") or "").strip()
        profile_rel_path = _safe_rel(rel)
        if profile_rel_path.parts[: len(profile_prefix)] != profile_prefix:
            continue

        profile_source = package_root / profile_rel_path
        profile_target = _target_for_rooted_rel(roots, profile_rel_path, "transfer driver profile import target")
        backups.append(_backup_target(profile_target, backup_root, roots))
        copied += _copy_any(profile_source, profile_target, file_progress)

        project_rel_path = _driver_project_rel_for_profile_item(item, profile_rel_path)
        if project_rel_path is not None:
            project_source = package_root / project_rel_path
            if project_source.exists():
                project_target = _target_for_rooted_rel(roots, project_rel_path, "transfer driver project import target")
                backups.append(_backup_target(project_target, backup_root, roots))
                copied += _copy_any(project_source, project_target, file_progress)
                _rewrite_imported_json_paths(project_target, roots)

        _rewrite_imported_json_paths(profile_target, roots)
        _rewrite_driver_transfer_paths(profile_target, roots)

    return _import_result(manifest, copied, backups)


def _import_replace_root(roots: TransferRoots, package_root: Path, backup_root: Path, manifest: dict[str, Any], target: Path, rel: str, file_progress: Callable[[Path], None] | None = None) -> dict[str, Any]:
    source = package_root / _safe_rel(rel)
    target = _assert_import_target(roots, target, "transfer replace-root import target")
    backups = [_backup_target(target, backup_root, roots)]
    copied = _copy_any(source, target, file_progress) if source.exists() else 0
    _rewrite_imported_json_paths(target, roots)
    return _import_result(manifest, copied, backups)


def _import_layer_studio(roots: TransferRoots, package_root: Path, backup_root: Path, manifest: dict[str, Any], file_progress: Callable[[Path], None] | None = None) -> dict[str, Any]:
    copied = 0
    backups: list[str] = []
    asset_mapping, library_copied, library_backups = _merge_layer_studio_library_from_bundle(roots, package_root, backup_root, file_progress)
    copied += library_copied
    backups.extend(library_backups)
    _rewrite_imported_json_paths(_layer_studio_library_root(roots), roots)
    return _import_result(manifest, copied, backups)


def _import_project_files(roots: TransferRoots, package_root: Path, backup_root: Path, manifest: dict[str, Any], file_progress: Callable[[Path], None] | None = None) -> dict[str, Any]:
    source_root = package_root / "LiveryProjects"
    copied = 0
    backups = []
    if source_root.exists():
        for source in source_root.rglob("*"):
            if not source.is_file() or not update_backup._project_file_allowed(source) or _is_layer_studio_project_path(source):
                continue
            rel = source.relative_to(source_root)
            target = _assert_import_target(roots, roots.livery_projects / rel, "transfer project file import target")
            backups.append(_backup_target(target, backup_root, roots))
            copied += _copy_any(source, target, file_progress)
            _rewrite_imported_json_paths(target, roots)
    return _import_result(manifest, copied, backups)


def _rewrite_driver_transfer_paths(profile_root: Path, roots: TransferRoots) -> None:
    manifest_path = profile_root / "manifest.json"
    if not manifest_path.exists():
        return
    manifest = _read_json(manifest_path, {})
    if not isinstance(manifest, dict):
        return
    car = str(manifest.get("carModel") or profile_root.parent.name)
    profile_id = str(manifest.get("id") or profile_root.name)
    project_root = roots.livery_projects / "Drivers" / car / profile_id
    manifest["manifestPath"] = str(manifest_path)
    manifest["assetRoot"] = str(profile_root)
    manifest["projectRoot"] = str(project_root)
    manifest["projectPath"] = str(project_root / "driver_project.json")
    manifest["projectAssetRoot"] = str(profile_root / "assets")
    manifest["updatedAt"] = datetime.now().isoformat(timespec="seconds")
    _write_json(manifest_path, manifest)

    project_path = project_root / "driver_project.json"
    project = _read_json(project_path, {})
    if not isinstance(project, dict):
        return
    project["projectRoot"] = str(project_root)
    project["projectPath"] = str(project_path)
    project["assetRoot"] = str(project_root / "assets")
    project["profileManifestPath"] = str(manifest_path)
    project["profileAssetRoot"] = str(profile_root)
    project["updatedAt"] = datetime.now().isoformat(timespec="seconds")
    _write_json(project_path, project)


def _import_result(manifest: dict[str, Any], copied: int, backups: list[str]) -> dict[str, Any]:
    kind = str(manifest.get("category") or manifest.get("kind") or "")
    return {
        "kind": kind,
        "label": str(manifest.get("label") or CATEGORY_LABELS.get(kind, "")),
        "importedFiles": copied,
        "itemCount": len(manifest.get("items") or []) if isinstance(manifest.get("items"), list) else 0,
        "backups": [backup for backup in backups if backup],
    }
