from __future__ import annotations

from pathlib import Path


TEMPLATE_CAR_ID = "ks_audi_r8_lms_gt4_evo"
TEMPLATE_SKIN_ID = "design_1"
TEMPLATE_SKIN_REL = f"content\\cars\\{TEMPLATE_CAR_ID}\\skins\\{TEMPLATE_SKIN_ID}"
TEMPLATE_MATERIAL_REL = f"{TEMPLATE_SKIN_REL}\\ext_skin_presentation.material"

MATERIAL_FILENAME = "ext_skin_design_pres.material"

TEXTURE_FILENAMES = {
    "base": "ext_skin_c.texture",
    "spat": "ext_skin_d.texture",
    "metalness": "ext_skin_m.texture",
    "roughness": "ext_skin_r.texture",
    "clearcoat": "ext_skin_cc.texture",
    "clearcoat_roughness": "ext_skin_cr.texture",
}

TEMPLATE_TEXTURE_RELS = {
    key: f"{TEMPLATE_SKIN_REL}\\{filename}"
    for key, filename in TEXTURE_FILENAMES.items()
}

SLOT_TO_TEXTURE_KEY = {
    "Base_BaseColorMap": "base",
    "SpatMap": "spat",
    "Base_MetalnessMap": "metalness",
    "Base_RoughnessMap": "roughness",
    "Base_ClearCoatMap": "clearcoat",
    "Base_ClearCoatRoughnessMap": "clearcoat_roughness",
}

AO_SLOT = "Base_AmbientOcclusionMap"

MATERIAL_MAP_FLAG_PARAMS = (
    "Base_HasMetalnessMap",
    "Base_HasRoughnessMap",
    "Base_HasClearCoatMap",
    "Base_HasClearCoatRoughnessMap",
)

MATERIAL_MAP_TEXTURE_SLOTS = (
    "Base_MetalnessMap",
    "Base_RoughnessMap",
    "Base_ClearCoatMap",
    "Base_ClearCoatRoughnessMap",
)

FINISH_KEY_TO_TEXTURE_KEY = {
    "metalness": "metalness",
    "roughness": "roughness",
    "clearCoat": "clearcoat",
    "clearCoatRoughness": "clearcoat_roughness",
}

DISABLED_BASE_MAP_FLAGS = MATERIAL_MAP_FLAG_PARAMS

SOLID_BC1_RGB565 = {
    "black": 0x0000,
    "white": 0xFFFF,
    "roughness_neutral": 0xBDF7,
}

SOLID_BC4_VALUES = {
    "black": 0,
    "white": 255,
    "roughness_neutral": 190,
}


def norm_slashes(value: str) -> str:
    return str(value or "").replace("/", "\\")


def split_content_path(path: str) -> list[str]:
    return [part for part in norm_slashes(path).split("\\") if part]


def is_car_level_ext_skin_material(car_content_path: str | None, material_ref: str | None) -> bool:
    if not car_content_path or not material_ref:
        return False
    car_prefix = norm_slashes(car_content_path).lower().rstrip("\\")
    normalized = norm_slashes(material_ref).lower()
    if "\\skins\\" in normalized:
        return False
    if not normalized.startswith(car_prefix + "\\materials\\"):
        return False
    name = Path(normalized.replace("\\", "/")).name
    return name.startswith("ext_skin") and name.endswith(".material")


def skin_rel(car_content_path: str, skin_id: str) -> str:
    return norm_slashes(f"{car_content_path}\\skins\\{skin_id}")


def material_rel(car_content_path: str, skin_id: str) -> str:
    return norm_slashes(f"{skin_rel(car_content_path, skin_id)}\\{MATERIAL_FILENAME}")


def local_texture_rel(car_content_path: str, skin_id: str, texture_key: str) -> str:
    return norm_slashes(f"{skin_rel(car_content_path, skin_id)}\\{TEXTURE_FILENAMES[texture_key]}")


def local_texture_replacements(car_content_path: str, skin_id: str, ao_ref: str | None = None) -> dict[str, str]:
    replacements = {
        slot: local_texture_rel(car_content_path, skin_id, key)
        for slot, key in SLOT_TO_TEXTURE_KEY.items()
    }
    if ao_ref:
        replacements[AO_SLOT] = norm_slashes(ao_ref)
    return replacements


def texture_override_slots() -> list[str]:
    slots = list(SLOT_TO_TEXTURE_KEY)
    slots.append(AO_SLOT)
    return slots


def solid_bc1_block(color_name: str) -> bytes:
    value = int(SOLID_BC1_RGB565[color_name])
    color = value.to_bytes(2, "little")
    return color + color + b"\x00\x00\x00\x00"


def solid_bc4_block(color_name: str) -> bytes:
    value = max(0, min(255, int(SOLID_BC4_VALUES[color_name])))
    return solid_bc4_value_block(value)


def solid_bc4_value_block(value: int) -> bytes:
    value = max(0, min(255, int(value)))
    return bytes([value, value]) + b"\x00\x00\x00\x00\x00\x00"


def default_solid_for_texture(texture_key: str) -> str:
    if texture_key == "base":
        return "white"
    if texture_key in {"spat", "metalness", "clearcoat"}:
        return "black"
    if texture_key == "roughness":
        return "roughness_neutral"
    if texture_key == "clearcoat_roughness":
        return "white"
    return "black"


def find_target_ao_ref(car_content_path: str, exists) -> str | None:
    for name in ("EXT_Skin_AO.texture", "ext_skin_ao.texture"):
        ref = norm_slashes(f"{car_content_path}\\textures\\{name}")
        if exists(ref):
            return ref
    return None
