use crate::define_store;
use crate::errors::AleaticoResult;
use crate::renderer::resources::pipelines::PipelineId;
use crate::renderer::resources::texture::TextureId;

define_store!(Material);

/// Descriptor to create a material
#[derive(Debug, Clone)]
pub struct MaterialDescriptor {
    /// Material debug label
    pub label: Option<String>,
    /// Textures of this material
    pub textures: MaterialTextures,
}

/// Possible textures of a material
#[derive(Debug, Default, Clone)]
pub struct MaterialTextures {
    /// Albedo texture
    pub albedo: Option<TextureId>,
    /// Normal map
    pub normal: Option<TextureId>,
}

impl MaterialDescriptor {
    /// Create a new [`MaterialDescriptor`]
    pub fn new() -> Self {
        Self {
            label: None,
            textures: MaterialTextures::default(),
        }
    }

    /// Create a new [`MaterialDescriptor`] with an albedo texture
    pub fn textured(albedo: TextureId) -> Self {
        Self {
            textures: MaterialTextures {
                albedo: Some(albedo),
                ..MaterialTextures::default()
            },
            ..Self::new()
        }
    }

    /// Set label
    pub fn with_label(mut self, label: impl Into<String>) -> Self {
        self.label = Some(label.into());
        self
    }

    /// Set albedo texture
    pub fn with_albedo(mut self, texture: TextureId) -> Self {
        self.textures.albedo = Some(texture);
        self
    }

    /// Set normal map texture
    pub fn with_normal(mut self, texture: TextureId) -> Self {
        self.textures.normal = Some(texture);
        self
    }
}

/// Represents a material
pub struct Material {
    /// Material debug label
    #[allow(unused)]
    pub(crate) label: Option<String>,
    /// Assigned pipeline ID
    pub(crate) pipeline_id: PipelineId,
    /// Textures of this material
    pub(crate) textures: MaterialTextures,
}

impl Material {
    /// Create a new [`Material`]
    pub fn new(pipeline_id: PipelineId, descriptor: MaterialDescriptor) -> AleaticoResult<Self> {
        Ok(Self {
            label: descriptor.label,
            pipeline_id,
            textures: descriptor.textures,
        })
    }
}
