from __future__ import annotations

import json
import re
import shutil
from datetime import datetime
from pathlib import Path
from typing import Any

from liverylab_core import (
    livery_identity,
    official_external_liveries,
    official_external_project_assets,
    official_external_workflow,
    official_saved_car_generation,
    official_saved_car_state,
    official_variant_compatibility,
    project_types,
    skin_policy,
)


PROJECT_MANIFEST = "official_external_project.json"
RUNTIME_SUFFIXES = {".texture", ".texturemips"}
PROJECT_DUPLICATE_CONTROL_FILES = {
    PROJECT_MANIFEST.lower(),
    official_external_liveries.EXTERNAL_LIVERY_JSON.lower(),
    official_external_project_assets.PREVIEW_PROJECT.lower(),
    "liverylab_skin.json",
    "readme.txt",
}
DEFAULT_MATERIAL_BATCHES = ("EXT_SKIN", "EXT_BANNER")
VEHICLE_VARIANT_METADATA_KEYS = (
    "id",
    "label",
    "source",
    "mechanicalPreset",
    "mechanicalPresetName",
    "mechanicalPresetShortName",
    "visualPreset",
    "visualPresetName",
    "visualPresetPresentation",
    "visualPresetExternalCustomizableKnown",
    "visualPresetExternalCustomizable",
    "visualPresetExternalCompatibilitySource",
    "carFinalState",
    "savedCarSource",
    "savedCarSourceSha256",
    "carData",
    "actorPath",
    "compatibleRim",
    "rimDesign",
    "cardesign",
    "startNumber",
)


def _safe_segment(value: Any, fallback: str = "official_external") -> str:
    raw = str(value or "").strip().lower().replace("\\", "_").replace("/", "_")
    raw = re.sub(r"[^a-z0-9._-]+", "_", raw)
    raw = re.sub(r"_+", "_", raw).strip("._-")
    return raw or fallback


def _vehicle_variant_metadata(value: Any) -> dict[str, Any]:
    if not isinstance(value, dict):
        return {}
    out: dict[str, Any] = {}
    for key in VEHICLE_VARIANT_METADATA_KEYS:
        item = value.get(key)
        if item is None:
            continue
        if isinstance(item, (str, int, float, bool)):
            text = str(item).strip() if isinstance(item, str) else item
            if text != "":
                out[key] = text
    return out


def _source_root(entry: dict[str, Any]) -> Path:
    root = Path(str(entry.get("local_root") or "")).expanduser()
    if not root.exists() or not root.is_dir():
        raise FileNotFoundError(f"Official external library copy not found: {root}")
    return root


def _project_identity(source_entry: dict[str, Any], project_name: str = "") -> dict[str, str]:
    car_model = _safe_segment(source_entry.get("car_model"), "car")
    base_skin_id = _safe_segment(source_entry.get("skin_id") or source_entry.get("display_name"), "official_livery")
    project_skin_id = _safe_segment(project_name, "") or f"{base_skin_id}_project"
    display_name = str(project_name or "").strip() or f"{source_entry.get('display_name') or base_skin_id} Project"
    return {
        "carModel": car_model,
        "skinId": project_skin_id,
        "displayName": display_name,
        "key": f"official_external_project:{car_model}:{project_skin_id}".lower(),
    }


def _new_project_identity(car_model: str, livery_name: str, external_folder_name: str = "", skin_id: str = "") -> dict[str, str]:
    clean_car = _safe_segment(car_model, "car")
    display_name = livery_identity.normalize_display_name(livery_name, "Official Livery")
    clean_skin_id = livery_identity.technical_skin_id(skin_id or display_name, "official_livery")
    clean_folder = livery_identity.external_folder_slug(
        external_folder_name or livery_identity.official_external_folder_name(clean_car, clean_skin_id),
        fallback="official_livery",
    )
    return {
        "carModel": clean_car,
        "skinId": clean_skin_id,
        "displayName": display_name,
        "externalFolderName": clean_folder,
        "key": f"official_external_project:{clean_car}:{clean_skin_id}".lower(),
    }


def project_folder_for_entry(projects_root: str | Path, source_entry: dict[str, Any], project_name: str = "") -> Path:
    identity = _project_identity(source_entry, project_name)
    return Path(projects_root).expanduser() / identity["carModel"] / identity["skinId"]


def new_project_folder(projects_root: str | Path, car_model: str, livery_name: str, external_folder_name: str = "", skin_id: str = "") -> Path:
    identity = _new_project_identity(car_model, livery_name, external_folder_name, skin_id)
    return Path(projects_root).expanduser() / identity["carModel"] / identity["skinId"]


def planned_external_folder_name(livery_name: str, external_folder_name: str = "", car_model: str = "car", skin_id: str = "") -> str:
    return _new_project_identity(car_model, livery_name, external_folder_name, skin_id)["externalFolderName"]


def initial_external_livery_json(car_guid: str = "") -> dict[str, Any]:
    return official_external_project_assets.initial_external_livery_json(car_guid)


def copy_library_sources_to_project(source_root: str | Path, project_folder: str | Path) -> dict[str, Any]:
    source = Path(source_root).expanduser()
    target = Path(project_folder).expanduser()
    if not source.exists() or not source.is_dir():
        raise FileNotFoundError(f"Official external library copy not found: {source}")
    target.mkdir(parents=True, exist_ok=True)
    copied: list[str] = []
    skipped_runtime: list[str] = []
    skipped_existing: list[str] = []
    for child in sorted((item for item in source.rglob("*") if item.is_file()), key=lambda item: item.relative_to(source).as_posix().lower()):
        rel = child.relative_to(source)
        if child.suffix.lower() in RUNTIME_SUFFIXES:
            skipped_runtime.append(rel.as_posix())
            continue
        destination = target / rel
        destination.parent.mkdir(parents=True, exist_ok=True)
        if destination.exists():
            skipped_existing.append(rel.as_posix())
            continue
        shutil.copy2(child, destination)
        copied.append(rel.as_posix())
    return {
        "sourceFolder": str(source),
        "projectFolder": str(target),
        "copied": copied,
        "copiedCount": len(copied),
        "skippedRuntime": skipped_runtime,
        "skippedRuntimeCount": len(skipped_runtime),
        "skippedExisting": skipped_existing,
        "skippedExistingCount": len(skipped_existing),
    }


def copy_project_authoring_assets(source_root: str | Path, project_folder: str | Path) -> dict[str, Any]:
    """Copy editable Official project assets without copying identity or deployment state."""
    source = Path(source_root).expanduser()
    target = Path(project_folder).expanduser()
    if not source.is_dir():
        raise FileNotFoundError(f"Official external project folder not found: {source}")
    if source.resolve() == target.resolve():
        raise ValueError("Official project duplicate source and target must be different")
    target.mkdir(parents=True, exist_ok=True)
    copied: list[str] = []
    skipped: list[str] = []
    for child in sorted((item for item in source.rglob("*") if item.is_file()), key=lambda item: item.relative_to(source).as_posix().lower()):
        rel = child.relative_to(source)
        name = child.name.lower()
        if name in PROJECT_DUPLICATE_CONTROL_FILES or child.suffix.lower() in RUNTIME_SUFFIXES or name.endswith(official_external_liveries.SAVED_CAR_SUFFIX.lower()):
            skipped.append(rel.as_posix())
            continue
        destination = target / rel
        destination.parent.mkdir(parents=True, exist_ok=True)
        shutil.copy2(child, destination)
        copied.append(rel.as_posix())
    return {
        "sourceFolder": str(source),
        "projectFolder": str(target),
        "copied": copied,
        "copiedCount": len(copied),
        "skipped": skipped,
        "skippedCount": len(skipped),
    }


def copy_external_livery_configuration(source_root: str | Path, project_folder: str | Path, car_guid: str) -> dict[str, Any]:
    source = Path(source_root).expanduser() / official_external_liveries.EXTERNAL_LIVERY_JSON
    target = Path(project_folder).expanduser() / official_external_liveries.EXTERNAL_LIVERY_JSON
    if not source.is_file():
        raise FileNotFoundError(f"Official project external_livery.json not found: {source}")
    loaded = json.loads(source.read_text(encoding="utf-8-sig"))
    if not isinstance(loaded, dict):
        raise ValueError("Official project external_livery.json must contain a JSON object")
    guid = official_saved_car_state.normalize_guid(car_guid)
    if not guid:
        raise ValueError("A valid new car_guid is required for an Official project duplicate")
    loaded["car_guid"] = guid
    official_external_liveries.write_external_livery_json(target, loaded)
    return {
        "sourcePath": str(source),
        "targetPath": str(target),
        "carGuid": guid,
    }


def _project_manifest(source_entry: dict[str, Any], project_entry: dict[str, Any], copy_result: dict[str, Any]) -> dict[str, Any]:
    source_details = source_entry.get("official_external") if isinstance(source_entry.get("official_external"), dict) else {}
    return official_external_project_assets.with_project_asset_metadata({
        "formatVersion": 1,
        "createdAt": project_entry.get("created_at") or datetime.now().isoformat(timespec="seconds"),
        "projectType": project_types.PROJECT_TYPE_OFFICIAL_EXTERNAL_LIVERY,
        "officialExternalRole": official_external_workflow.ROLE_PROJECT,
        "sourceLibraryKey": source_entry.get("key") or "",
        "sourceLibraryRoot": source_entry.get("local_root") or "",
        "sourceDescriptorId": source_details.get("sourceDescriptorId") or "",
        "deploymentTarget": official_external_workflow.DEPLOYMENT_TARGET_SAVED_GAMES_EXTERNAL_LIVERIES,
        "project": {
            "key": project_entry.get("key") or "",
            "skinId": project_entry.get("skin_id") or "",
            "displayName": project_entry.get("display_name") or "",
            "carModel": project_entry.get("car_model") or "",
            "carGuid": project_entry.get("car_guid") or "",
        },
        "copy": copy_result,
    }, project_entry.get("local_root") or "")


def _new_project_manifest(project_entry: dict[str, Any], metadata: dict[str, Any], created_files: list[str]) -> dict[str, Any]:
    details = project_entry.get("official_external") if isinstance(project_entry.get("official_external"), dict) else {}
    return official_external_project_assets.with_project_asset_metadata({
        "formatVersion": 1,
        "createdAt": project_entry.get("created_at") or datetime.now().isoformat(timespec="seconds"),
        "projectType": project_types.PROJECT_TYPE_OFFICIAL_EXTERNAL_LIVERY,
        "officialExternalRole": official_external_workflow.ROLE_PROJECT,
        "deploymentTarget": official_external_workflow.DEPLOYMENT_TARGET_SAVED_GAMES_EXTERNAL_LIVERIES,
        "externalFolderName": details.get("externalFolderName") or "",
        "metadata": metadata,
        "project": {
            "key": project_entry.get("key") or "",
            "skinId": project_entry.get("skin_id") or "",
            "displayName": project_entry.get("display_name") or "",
            "carModel": project_entry.get("car_model") or "",
            "carGuid": project_entry.get("car_guid") or "",
            "vehicleVariant": details.get("vehicleVariant") or {},
        },
        "createdFiles": created_files,
    }, project_entry.get("local_root") or "")


def _append_preview_created_files(created_files: list[str], preview_assets: dict[str, Any]) -> None:
    def add(name: str) -> None:
        clean = str(name or "").strip()
        if clean and clean not in created_files:
            created_files.append(clean)

    if preview_assets.get("previewProjectWritten"):
        add(official_external_project_assets.PREVIEW_PROJECT)
    if preview_assets.get("projectUvTemplate", {}).get("exists"):
        add("EXT_SKIN_UV.png")
    if preview_assets.get("projectPartsUvTemplate", {}).get("exists"):
        add("EXT_SKIN_PARTS_UV.png")
    neutral = preview_assets.get("neutralTexture") if isinstance(preview_assets.get("neutralTexture"), dict) else {}
    neutral_texture = neutral.get("texture") if isinstance(neutral.get("texture"), dict) else {}
    if neutral.get("created"):
        add(str(neutral_texture.get("name") or Path(str(neutral_texture.get("path") or "")).name))
    placeholders = preview_assets.get("placeholders") if isinstance(preview_assets.get("placeholders"), dict) else {}
    for item in placeholders.get("items") or []:
        if not isinstance(item, dict) or not item.get("created"):
            continue
        texture = item.get("texture") if isinstance(item.get("texture"), dict) else {}
        add(str(texture.get("name") or item.get("filename") or ""))
    if int(placeholders.get("createdCount") or 0) > 0:
        add(official_external_project_assets.PLACEHOLDER_STATE)


def make_project_entry(
    source_entry: dict[str, Any],
    project_folder: str | Path,
    *,
    project_name: str = "",
    game_root: str | Path | None = None,
) -> dict[str, Any]:
    identity = _project_identity(source_entry, project_name)
    source_details = source_entry.get("official_external") if isinstance(source_entry.get("official_external"), dict) else {}
    inspected = official_external_liveries.inspect_external_livery_folder(project_folder)
    texture_set = inspected.get("textureSet") if isinstance(inspected.get("textureSet"), dict) else {}
    primary_texture = texture_set.get("primaryTexture") if isinstance(texture_set.get("primaryTexture"), dict) else {}
    now = datetime.now().isoformat(timespec="seconds")
    entry = {
        "key": identity["key"],
        "skin_id": identity["skinId"],
        "display_name": identity["displayName"],
        "car_model": identity["carModel"],
        "car_guid": str(inspected.get("carGuid") or source_entry.get("car_guid") or ""),
        "car_content_path": source_entry.get("car_content_path") or f"content\\cars\\{identity['carModel']}",
        "game_root": str(game_root or source_entry.get("game_root") or ""),
        "created_at": now,
        "origin": skin_policy.ORIGIN_CREATED,
        "project_type": project_types.PROJECT_TYPE_OFFICIAL_EXTERNAL_LIVERY,
        "project_state": skin_policy.PROJECT_STATE_EDITABLE,
        "managed_by": "liverylab",
        "liverylab_managed": True,
        "active": False,
        "local_root": str(Path(project_folder).expanduser()),
        "files": {
            "external_livery_json": official_external_liveries.EXTERNAL_LIVERY_JSON,
            "primary_texture": str(primary_texture.get("path") or "").replace("\\", "/"),
        },
        "official_external": {
            "role": official_external_workflow.ROLE_PROJECT,
            "roleLabel": official_external_workflow.role_label(official_external_workflow.ROLE_PROJECT),
            "storageRole": official_external_workflow.STORAGE_ROLE_LIVERY_PROJECTS,
            "deploymentTarget": official_external_workflow.DEPLOYMENT_TARGET_SAVED_GAMES_EXTERNAL_LIVERIES,
            "sourceLibraryKey": source_entry.get("key") or "",
            "sourceLibraryRoot": source_entry.get("local_root") or "",
            "sourceDescriptorId": source_details.get("sourceDescriptorId") or "",
            "sourceFolder": source_details.get("sourceFolder") or "",
            "sourceFolderName": source_details.get("sourceFolderName") or "",
            "savedCarFound": bool(source_details.get("savedCarFound")),
            "savedCarPaths": list(source_details.get("savedCarPaths") or []),
            "descriptor": source_details.get("descriptor") or {},
            "deploymentStatus": "project_not_deployed",
        },
        "official_external_role": official_external_workflow.ROLE_PROJECT,
        "storage_role": official_external_workflow.STORAGE_ROLE_LIVERY_PROJECTS,
        "deployment_target": official_external_workflow.DEPLOYMENT_TARGET_SAVED_GAMES_EXTERNAL_LIVERIES,
        "editable_project": True,
    }
    return entry


def make_new_project_entry(
    project_folder: str | Path,
    *,
    livery_name: str,
    car_model: str,
    external_folder_name: str,
    skin_id: str = "",
    car_guid: str = "",
    game_root: str | Path | None = None,
    author: str = "",
    description: str = "",
    vehicle_variant: dict[str, Any] | None = None,
) -> dict[str, Any]:
    identity = _new_project_identity(car_model, livery_name, external_folder_name, skin_id)
    now = datetime.now().isoformat(timespec="seconds")
    folder = Path(project_folder).expanduser()
    metadata = {
        "author": str(author or "").strip(),
        "description": str(description or "").strip()[:96].strip(),
    }
    variant = _vehicle_variant_metadata(vehicle_variant)
    if variant:
        metadata["vehicleVariant"] = variant
    entry = {
        "key": identity["key"],
        "skin_id": identity["skinId"],
        "display_name": identity["displayName"],
        "car_model": identity["carModel"],
        "car_guid": str(car_guid or "").strip(),
        "car_content_path": f"content\\cars\\{identity['carModel']}",
        "game_root": str(game_root or ""),
        "created_at": now,
        "origin": skin_policy.ORIGIN_CREATED,
        "project_type": project_types.PROJECT_TYPE_OFFICIAL_EXTERNAL_LIVERY,
        "project_state": skin_policy.PROJECT_STATE_EDITABLE,
        "managed_by": "liverylab",
        "liverylab_managed": True,
        "identity_locked": True,
        "active": False,
        "local_root": str(folder),
        "files": {
            "external_livery_json": official_external_liveries.EXTERNAL_LIVERY_JSON,
            "primary_texture": "",
        },
        "official_external": {
            "role": official_external_workflow.ROLE_PROJECT,
            "roleLabel": official_external_workflow.role_label(official_external_workflow.ROLE_PROJECT),
            "storageRole": official_external_workflow.STORAGE_ROLE_LIVERY_PROJECTS,
            "deploymentTarget": official_external_workflow.DEPLOYMENT_TARGET_SAVED_GAMES_EXTERNAL_LIVERIES,
            "externalFolderName": identity["externalFolderName"],
            "plannedExternalFolder": identity["externalFolderName"],
            "sourceFolderName": identity["externalFolderName"],
            "identityLocked": True,
            "savedCarFound": False,
            "savedCarPaths": [],
            "deploymentStatus": "project_not_deployed",
            "metadata": metadata,
            "vehicleVariant": variant,
            "vehicleVariantLabel": variant.get("label") or "",
            "mechanicalPreset": variant.get("mechanicalPreset") or "",
            "visualPreset": variant.get("visualPreset") or "",
            "carFinalState": variant.get("carFinalState") or "",
        },
        "official_external_role": official_external_workflow.ROLE_PROJECT,
        "storage_role": official_external_workflow.STORAGE_ROLE_LIVERY_PROJECTS,
        "deployment_target": official_external_workflow.DEPLOYMENT_TARGET_SAVED_GAMES_EXTERNAL_LIVERIES,
        "editable_project": True,
    }
    if variant:
        entry["vehicle_variant"] = variant
    return entry


def import_editable_project(
    project_folder: str | Path,
    skin_manifest: dict[str, Any],
    *,
    game_root: str | Path | None = None,
    preview_assets_root: str | Path | None = None,
) -> dict[str, Any]:
    folder = Path(project_folder).expanduser()
    skin = skin_manifest if isinstance(skin_manifest, dict) else {}
    if not folder.exists() or not folder.is_dir():
        raise FileNotFoundError(f"Imported Official project folder not found: {folder}")
    external_json = folder / official_external_liveries.EXTERNAL_LIVERY_JSON
    if not external_json.is_file():
        raise FileNotFoundError(f"Imported Official project is missing {official_external_liveries.EXTERNAL_LIVERY_JSON}")

    source_details = skin.get("officialExternal") if isinstance(skin.get("officialExternal"), dict) else {}
    metadata = source_details.get("metadata") if isinstance(source_details.get("metadata"), dict) else {}
    variant = _vehicle_variant_metadata(
        source_details.get("vehicleVariant")
        or metadata.get("vehicleVariant")
        or skin.get("vehicleVariant")
    )
    if preview_assets_root and variant:
        variant, _visual_status = official_variant_compatibility.enrich_vehicle_variant(
            preview_assets_root,
            variant,
        )
    display_name = str(skin.get("displayName") or skin.get("skinId") or "Imported Official Livery").strip()
    car_model = str(skin.get("carModel") or "").strip()
    skin_id = str(skin.get("skinId") or "").strip()
    external_folder_name = str(
        skin.get("externalFolderName")
        or source_details.get("externalFolderName")
        or source_details.get("plannedExternalFolder")
        or source_details.get("sourceFolderName")
        or skin_id
    ).strip()
    expected_guid = official_saved_car_state.normalize_guid(
        skin.get("carGuid")
        or source_details.get("carGuid")
        or source_details.get("linkedSavedCarGuid")
    )
    if not car_model or not skin_id:
        raise ValueError("Editable Official package is missing its car model or skin id")

    saved_car_candidates = sorted(
        path for path in folder.rglob(f"*{official_saved_car_state.SAVED_CAR_SUFFIX}")
        if path.is_file()
    )
    if len(saved_car_candidates) > 1:
        raise ValueError("Editable Official package contains more than one project SavedCar")
    saved_car_path = saved_car_candidates[0] if saved_car_candidates else None
    saved_car_inspection: dict[str, Any] = {}
    if saved_car_path:
        saved_car_inspection = official_saved_car_state.inspect_saved_car_file(saved_car_path)
        if not saved_car_inspection.get("valid"):
            errors = saved_car_inspection.get("errors") if isinstance(saved_car_inspection.get("errors"), list) else []
            raise ValueError("Imported Official project SavedCar is invalid: " + "; ".join(str(row) for row in errors[:5]))
        saved_car_model = str(saved_car_inspection.get("carModel") or "").strip()
        if saved_car_model and saved_car_model.lower() != car_model.lower():
            raise ValueError(f"Imported Official project SavedCar targets {saved_car_model}, expected {car_model}")
        saved_car_guid = official_saved_car_state.official_livery_guid(saved_car_inspection)
        if expected_guid and not official_saved_car_state.matches_official_livery_guid(saved_car_inspection, expected_guid):
            raise ValueError("Imported Official project SavedCar GUID does not match the package manifest")
        expected_guid = saved_car_guid or expected_guid

    entry = make_new_project_entry(
        folder,
        livery_name=display_name,
        car_model=car_model,
        external_folder_name=external_folder_name,
        skin_id=skin_id,
        car_guid=expected_guid,
        game_root=game_root,
        author=str(metadata.get("author") or ""),
        description=str(metadata.get("description") or ""),
        vehicle_variant=variant,
    )
    entry["created_at"] = str(skin.get("createdAt") or entry.get("created_at") or "")
    entry["imported_at"] = datetime.now().isoformat(timespec="seconds")
    entry["active"] = False
    details = entry.get("official_external") if isinstance(entry.get("official_external"), dict) else {}
    details["deploymentStatus"] = "project_not_deployed"
    details["deployed"] = False
    material_batch = str(source_details.get("materialBatch") or "").strip()
    if material_batch:
        details["materialBatch"] = material_batch

    primary_texture = folder / "EXT_Skin_C.png"
    if primary_texture.is_file():
        entry.setdefault("files", {})["primary_texture"] = primary_texture.name
    thumbnail = folder / "livery_thumbnail.png"
    if thumbnail.is_file():
        entry["project_thumbnail_disk_path"] = str(thumbnail)
        entry["thumbnail_png_disk_path"] = str(thumbnail)
        entry.setdefault("files", {})["thumbnail_png"] = thumbnail.name
        details.setdefault("metadata", {})["thumbnail"] = str(thumbnail)

    saved_car_metadata: dict[str, Any] = {}
    if saved_car_path:
        relative_saved_car = saved_car_path.relative_to(folder).as_posix()
        source_generated = source_details.get("generatedSavedCar") if isinstance(source_details.get("generatedSavedCar"), dict) else {}
        saved_car_metadata = {
            key: value
            for key, value in source_generated.items()
            if key not in {"path", "deployedPath", "deployedAt", "lastDeployedPath", "deploymentStatus"}
        }
        saved_car_metadata.update({
            "sourceType": official_saved_car_generation.SOURCE_LIVERYLAB_GENERATED,
            "relativePath": relative_saved_car,
            "path": str(saved_car_path),
            "filename": saved_car_path.name,
            "carGuid": expected_guid,
            "instanceCarGuid": saved_car_inspection.get("carGuid") or "",
            "liveryLinkerGuid": saved_car_inspection.get("liveryLinkerGuid") or "",
            "carModel": car_model,
            "size": saved_car_path.stat().st_size,
            "deploymentStatus": "prepared_local",
        })
        entry.setdefault("files", {})["saved_car"] = relative_saved_car
        details["savedCarSource"] = official_saved_car_generation.SOURCE_LIVERYLAB_GENERATED
        details["generatedSavedCar"] = saved_car_metadata
        details["linkedSavedCarGuid"] = expected_guid
        details["savedCarFound"] = False
        details["savedCarPaths"] = []
        details["savedCarDeploymentStatus"] = "prepared_local"
    entry["official_external"] = details

    preview_assets = official_external_project_assets.prepare_project_preview_assets(
        folder,
        entry,
        preview_assets_root=preview_assets_root,
        overwrite_uv=False,
    )
    created_files = sorted(
        path.relative_to(folder).as_posix()
        for path in folder.rglob("*")
        if path.is_file() and path.name != PROJECT_MANIFEST
    )
    clean_metadata = {
        "author": str(metadata.get("author") or "").strip(),
        "description": str(metadata.get("description") or "").strip()[:96].strip(),
        "thumbnail": str(thumbnail) if thumbnail.is_file() else "",
    }
    if variant:
        clean_metadata["vehicleVariant"] = variant
    manifest = _new_project_manifest(entry, clean_metadata, created_files)
    manifest["previewAssets"] = preview_assets
    if saved_car_metadata:
        manifest["savedCar"] = saved_car_metadata
    manifest["updatedAt"] = datetime.now().isoformat(timespec="seconds")
    manifest_path = folder / PROJECT_MANIFEST
    manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False), encoding="utf-8")
    return {
        "entry": entry,
        "projectFolder": str(folder),
        "manifestPath": str(manifest_path),
        "previewAssets": preview_assets,
        "savedCar": saved_car_metadata,
        "manifest": manifest,
    }


def create_project_from_library_entry(
    source_entry: dict[str, Any],
    projects_root: str | Path,
    *,
    project_name: str = "",
    game_root: str | Path | None = None,
    preview_assets_root: str | Path | None = None,
    overwrite: bool = False,
) -> dict[str, Any]:
    role = official_external_workflow.role_for_entry(source_entry)
    if not official_external_workflow.is_official_external_type(source_entry) or role != official_external_workflow.ROLE_LIBRARY:
        raise ValueError("Only installed official external library copies can be converted into editable projects.")
    source_root = _source_root(source_entry)
    project_folder = project_folder_for_entry(projects_root, source_entry, project_name)
    if project_folder.exists() and any(project_folder.iterdir()) and not overwrite:
        raise FileExistsError(f"Official external project folder already exists: {project_folder}")
    copy_result = copy_library_sources_to_project(source_root, project_folder)
    readme_path = official_external_project_assets.write_project_readme(project_folder)
    entry = make_project_entry(source_entry, project_folder, project_name=project_name, game_root=game_root)
    manifest = _project_manifest(source_entry, entry, copy_result)
    preview_assets = official_external_project_assets.prepare_project_preview_assets(
        project_folder,
        entry,
        preview_assets_root=preview_assets_root,
        overwrite_uv=overwrite,
    )
    generated_files: list[str] = []
    _append_preview_created_files(generated_files, preview_assets)
    if generated_files:
        manifest["generatedFiles"] = generated_files
    manifest["previewAssets"] = preview_assets
    manifest_path = project_folder / PROJECT_MANIFEST
    manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False), encoding="utf-8")
    return {
        "entry": entry,
        "projectFolder": str(project_folder),
        "manifestPath": str(manifest_path),
        "readmePath": str(readme_path),
        "copy": copy_result,
        "previewAssets": preview_assets,
        "manifest": manifest,
    }


def create_new_project(
    projects_root: str | Path,
    *,
    livery_name: str,
    car_model: str,
    external_folder_name: str = "",
    skin_id: str = "",
    car_guid: str = "",
    game_root: str | Path | None = None,
    author: str = "",
    description: str = "",
    thumbnail: str | Path | None = None,
    vehicle_variant: dict[str, Any] | None = None,
    preview_assets_root: str | Path | None = None,
    auto_generate_saved_car: bool = False,
    saved_car_source: str | Path | None = None,
    reserved_saved_car_guids: list[str] | None = None,
    overwrite: bool = False,
) -> dict[str, Any]:
    if not str(livery_name or "").strip():
        raise ValueError("Livery name is required")
    if not str(car_model or "").strip():
        raise ValueError("Target car is required for an official external project")
    identity = _new_project_identity(car_model, livery_name, external_folder_name, skin_id)
    variant = _vehicle_variant_metadata(vehicle_variant)
    generated_saved_car: dict[str, Any] = {}
    source_status: dict[str, Any] = {}
    effective_car_guid = str(car_guid or "").strip()
    explicit_saved_car_source = Path(saved_car_source).expanduser() if saved_car_source else None
    if explicit_saved_car_source is not None:
        generated_saved_car = official_saved_car_generation.generate_saved_car(
            explicit_saved_car_source,
            expected_car_model=identity["carModel"],
            reserved_guids=reserved_saved_car_guids,
        )
        source_status = {
            "path": str(explicit_saved_car_source),
            "relativePath": "",
            "sourceType": "project_duplicate",
        }
        effective_car_guid = str(generated_saved_car.get("carGuid") or "").strip()
    elif auto_generate_saved_car:
        if not preview_assets_root:
            raise ValueError("Official Preview Assets are required to generate a SavedCar.")
        source_status = official_saved_car_generation.resolve_variant_final_state(
            preview_assets_root,
            identity["carModel"],
            variant,
        )
        if not source_status.get("ready"):
            errors = source_status.get("errors") if isinstance(source_status.get("errors"), list) else []
            raise ValueError("SavedCar generation source is not ready: " + "; ".join(str(row) for row in errors[:5]))
        generated_saved_car = official_saved_car_generation.generate_saved_car(
            source_status["path"],
            expected_car_model=identity["carModel"],
            reserved_guids=reserved_saved_car_guids,
        )
        effective_car_guid = str(generated_saved_car.get("carGuid") or "").strip()
    project_folder = new_project_folder(projects_root, identity["carModel"], identity["displayName"], identity["externalFolderName"], identity["skinId"])
    if project_folder.exists() and any(project_folder.iterdir()) and not overwrite:
        raise FileExistsError(f"Official external project folder already exists: {project_folder}")
    project_folder.mkdir(parents=True, exist_ok=True)
    created_files: list[str] = []

    saved_car_metadata: dict[str, Any] = {}
    if generated_saved_car:
        saved_car_metadata = official_saved_car_generation.write_project_saved_car(
            project_folder,
            generated_saved_car,
            source_relative_path=str(source_status.get("relativePath") or ""),
            overwrite=overwrite,
        )
        created_files.append(str(saved_car_metadata.get("relativePath") or ""))

    external_json_path = project_folder / official_external_liveries.EXTERNAL_LIVERY_JSON
    if not external_json_path.exists() or overwrite:
        official_external_liveries.write_external_livery_json(external_json_path, initial_external_livery_json(effective_car_guid))
        created_files.append(external_json_path.name)

    readme_path = official_external_project_assets.write_project_readme(project_folder, overwrite=overwrite)
    if readme_path.name not in created_files:
        created_files.append(readme_path.name)

    thumbnail_path = ""
    source_thumbnail = Path(str(thumbnail or "")).expanduser() if str(thumbnail or "").strip() else None
    if source_thumbnail and source_thumbnail.exists() and source_thumbnail.is_file():
        target_thumbnail = project_folder / "livery_thumbnail.png"
        if not target_thumbnail.exists() or overwrite:
            shutil.copy2(source_thumbnail, target_thumbnail)
            created_files.append(target_thumbnail.name)
        thumbnail_path = str(target_thumbnail)

    metadata = {
        "author": str(author or "").strip(),
        "description": str(description or "").strip()[:96].strip(),
        "thumbnail": thumbnail_path,
    }
    if variant:
        metadata["vehicleVariant"] = variant
    entry = make_new_project_entry(
        project_folder,
        livery_name=identity["displayName"],
        car_model=identity["carModel"],
        external_folder_name=identity["externalFolderName"],
        skin_id=identity["skinId"],
        car_guid=effective_car_guid,
        game_root=game_root,
        author=author,
        description=description,
        vehicle_variant=variant,
    )
    if saved_car_metadata:
        entry.setdefault("files", {})["saved_car"] = saved_car_metadata["relativePath"]
        details = entry.get("official_external") if isinstance(entry.get("official_external"), dict) else {}
        details["savedCarSource"] = official_saved_car_generation.SOURCE_LIVERYLAB_GENERATED
        details["generatedSavedCar"] = saved_car_metadata
        details["linkedSavedCarGuid"] = effective_car_guid
        details["savedCarFound"] = False
        details["savedCarPaths"] = []
        details["savedCarDeploymentStatus"] = "prepared_local"
        entry["official_external"] = details
    if thumbnail_path:
        entry["project_thumbnail_disk_path"] = thumbnail_path
        entry["thumbnail_png_disk_path"] = thumbnail_path
        entry.setdefault("files", {})["thumbnail_png"] = "livery_thumbnail.png"
    manifest = _new_project_manifest(entry, metadata, created_files)
    preview_assets = official_external_project_assets.prepare_project_preview_assets(
        project_folder,
        entry,
        preview_assets_root=preview_assets_root,
        overwrite_uv=overwrite,
    )
    _append_preview_created_files(created_files, preview_assets)
    manifest["createdFiles"] = created_files
    manifest["previewAssets"] = preview_assets
    if saved_car_metadata:
        manifest["savedCar"] = saved_car_metadata
    manifest_path = project_folder / PROJECT_MANIFEST
    manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False), encoding="utf-8")
    return {
        "entry": entry,
        "projectFolder": str(project_folder),
        "manifestPath": str(manifest_path),
        "readmePath": str(readme_path),
        "externalLiveryJson": str(external_json_path),
        "externalFolderName": identity["externalFolderName"],
        "createdFiles": created_files,
        "previewAssets": preview_assets,
        "savedCar": saved_car_metadata,
        "manifest": manifest,
    }
