from __future__ import annotations

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

from liverylab_core import official_package_validation, official_saved_car_generation


REGISTRATION_STATE_UNREGISTERED = "unregistered"
REGISTRATION_STATE_REGISTERED = "registered"


def registration_readiness(descriptor: dict[str, Any]) -> dict[str, Any]:
    blockers: list[str] = []
    if descriptor.get("valid") is not True:
        blockers.append("The ExternalLivery folder is not valid.")
    texture_set = descriptor.get("textureSet") if isinstance(descriptor.get("textureSet"), dict) else {}
    missing_references = int(texture_set.get("missingReferenceCount") or 0)
    if missing_references:
        blockers.append(f"{missing_references} referenced texture file(s) are missing.")
    saved_car_paths = [
        str(value or "").strip()
        for value in descriptor.get("savedCarPaths") or []
        if str(value or "").strip()
    ]
    if not saved_car_paths:
        blockers.append("No matching Garage SavedCar was found.")
    elif len(saved_car_paths) > 1:
        blockers.append("More than one matching Garage SavedCar was found; the profile target is ambiguous.")
    return {
        "ready": not blockers,
        "blockers": blockers,
        "savedCarCount": len(saved_car_paths),
        "missingReferenceCount": missing_references,
    }


def validate_registration_source(
    descriptor: dict[str, Any],
    entry: dict[str, Any],
) -> dict[str, Any]:
    source = Path(str(descriptor.get("externalLiveryFolder") or "")).expanduser()
    result = official_package_validation.validate_payload(
        source,
        entry,
        allow_linked_saved_car=True,
    )
    result["registrationReadiness"] = registration_readiness(descriptor)
    for blocker in result["registrationReadiness"].get("blockers") or []:
        if blocker not in result["errors"]:
            result["errors"].append(blocker)
    result["ready"] = not result["errors"]
    return result


def copy_validated_registration_payload(
    validation: dict[str, Any],
    target_folder: str | Path,
) -> dict[str, Any]:
    if validation.get("ready") is not True:
        raise ValueError("Official external registration validation is not ready.")
    source_root = Path(str(validation.get("payloadRoot") or "")).expanduser().resolve()
    target = Path(target_folder).expanduser()
    if target.exists():
        raise FileExistsError(f"Official registration target already exists: {target}")
    target.mkdir(parents=True, exist_ok=True)
    copied: list[dict[str, Any]] = []
    for row in validation.get("copyPlan") or []:
        if not isinstance(row, dict):
            continue
        source = Path(str(row.get("source") or "")).expanduser().resolve()
        try:
            relative = source.relative_to(source_root)
        except ValueError as exc:
            raise ValueError(f"Official registration source escapes its ExternalLivery folder: {source}") from exc
        destination = target / relative
        destination.parent.mkdir(parents=True, exist_ok=True)
        shutil.copy2(source, destination)
        copied.append({
            "kind": row.get("kind") or "official_external_file",
            "source": str(source),
            "target": str(destination),
            "relativePath": relative.as_posix(),
            "size": destination.stat().st_size,
        })

    saved_car = validation.get("savedCar") if isinstance(validation.get("savedCar"), dict) else {}
    saved_car_source = Path(str(saved_car.get("path") or "")).expanduser().resolve()
    if not saved_car_source.is_file():
        raise FileNotFoundError("Validated Official registration SavedCar is missing.")
    saved_car_relative = Path(official_saved_car_generation.PROJECT_SAVED_CAR_DIRNAME) / saved_car_source.name
    saved_car_target = target / saved_car_relative
    saved_car_target.parent.mkdir(parents=True, exist_ok=True)
    shutil.copy2(saved_car_source, saved_car_target)
    copied.append({
        "kind": "saved_car",
        "source": str(saved_car_source),
        "target": str(saved_car_target),
        "relativePath": saved_car_relative.as_posix(),
        "size": saved_car_target.stat().st_size,
        "sha256": saved_car.get("sha256") or "",
    })
    return {
        "targetFolder": str(target),
        "copied": copied,
        "copiedCount": len(copied),
        "savedCar": {
            **saved_car,
            "path": str(saved_car_target),
            "relativePath": saved_car_relative.as_posix(),
            "sourceType": official_saved_car_generation.SOURCE_REGISTERED_EXTERNAL,
        },
        "registeredAt": datetime.now().isoformat(timespec="seconds"),
    }


def registered_saved_car_metadata(saved_car: dict[str, Any]) -> dict[str, Any]:
    filename = Path(str(saved_car.get("filename") or saved_car.get("path") or "")).name
    relative_path = str(saved_car.get("relativePath") or Path("SavedCar") / filename).replace("\\", "/")
    return {
        "sourceType": official_saved_car_generation.SOURCE_REGISTERED_EXTERNAL,
        "relativePath": relative_path,
        "filename": filename,
        "carGuid": str(saved_car.get("carGuid") or ""),
        "instanceCarGuid": str(saved_car.get("instanceCarGuid") or ""),
        "liveryLinkerGuid": str(saved_car.get("liveryLinkerGuid") or ""),
        "carModel": str(saved_car.get("carModel") or ""),
        "sha256": str(saved_car.get("sha256") or ""),
        "size": int(saved_car.get("size") or 0),
        "createdAt": datetime.now().isoformat(timespec="seconds"),
        "deploymentStatus": "existing",
    }
