//! Runtime and legacy-compatible material descriptor types.

use bevy::prelude::*;
use serde::{Deserialize, Serialize};

use crate::{
    ColorDesc, ComponentInstanceId, EditorAssetRef, MaterialParameter, MaterialTextureBinding,
    ShaderRefDesc,
};

/// Per-render-slot material override stored on scene actors.
#[derive(Reflect, Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[reflect(Default, Debug, PartialEq, Serialize, Deserialize)]
#[type_path = "shared::components"]
pub struct MaterialSlotOverride {
    pub slot_id: ComponentInstanceId,
    #[serde(default)]
    pub base_material: Option<EditorAssetRef>,
    pub material: MaterialDesc,
}

/// Actor-level material overrides retained for legacy scene upgrade only.
#[derive(Component, Reflect, Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[reflect(Component, Default, Debug, PartialEq, Serialize, Deserialize)]
#[type_path = "shared::components"]
pub struct MaterialOverride {
    #[serde(default)]
    pub slots: Vec<MaterialSlotOverride>,
}

/// Resolved runtime and legacy-compatible material representation. Project authoring uses
/// `MaterialAsset`/`MaterialInputSet`; hydration maps this descriptor to renderer materials.
#[derive(Component, Reflect, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[reflect(Component, Default, Debug, Serialize, Deserialize)]
#[type_path = "shared::components"]
pub struct MaterialDesc {
    #[serde(default)]
    pub shader: ShaderRefDesc,
    pub base_color: ColorDesc,
    pub metallic: f32,
    pub roughness: f32,
    #[serde(default = "default_emissive_color")]
    pub emissive_color: ColorDesc,
    #[serde(default)]
    pub emissive_intensity: f32,
    pub base_color_texture: Option<String>,
    #[serde(default)]
    pub emissive_texture: Option<String>,
    pub normal_map_texture: Option<String>,
    pub metallic_roughness_texture: Option<String>,
    #[serde(default)]
    pub occlusion_texture: Option<String>,
    #[serde(default)]
    pub material_asset_path: Option<String>,
    #[serde(default)]
    pub parameters: Vec<MaterialParameter>,
    #[serde(default)]
    pub textures: Vec<MaterialTextureBinding>,
    #[serde(default)]
    pub uv_offset: Vec2,
    #[serde(default = "default_material_uv_tiling")]
    pub uv_tiling: Vec2,
}

impl MaterialDesc {
    pub fn new(base_color: ColorDesc, metallic: f32, roughness: f32) -> Self {
        Self {
            shader: ShaderRefDesc::default(),
            base_color,
            metallic,
            roughness,
            emissive_color: default_emissive_color(),
            emissive_intensity: 0.0,
            base_color_texture: None,
            emissive_texture: None,
            normal_map_texture: None,
            metallic_roughness_texture: None,
            occlusion_texture: None,
            material_asset_path: None,
            parameters: Vec::new(),
            textures: Vec::new(),
            uv_offset: Vec2::ZERO,
            uv_tiling: Vec2::ONE,
        }
    }
}

fn default_material_uv_tiling() -> Vec2 {
    Vec2::ONE
}

fn default_emissive_color() -> ColorDesc {
    ColorDesc::srgb(1.0, 1.0, 1.0)
}

impl Default for MaterialDesc {
    fn default() -> Self {
        Self::new(ColorDesc::default(), 0.0, 0.65)
    }
}
