//! Light component definitions.

use serde::{Deserialize, Serialize};

/// Type of light source. Directional, point, and spot follow glTF
/// KHR_lights_punctual. Area is an emitter with spatial extent shaded with
/// linearly transformed cosines.
#[derive(Default, Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum LightType {
    /// Infinitely distant light (like the sun). Uses entity's -Z direction.
    #[default]
    Directional,
    /// Omnidirectional point light. Uses entity's position.
    Point,
    /// Cone-shaped spotlight. Uses entity's position and -Z direction.
    Spot,
    /// Emitter with spatial extent (rectangle, disk, sphere, or tube). The
    /// extent and shape come from the area fields on [`Light`].
    Area,
}

/// Geometric shape of an area light's emitter surface.
#[derive(Default, Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum AreaLightShape {
    /// Flat rectangle oriented in the entity's local XY plane, emitting along
    /// -Z. Sized by `area_width` and `area_height`. Supports an emissive texture.
    #[default]
    Rectangle,
    /// Flat disk oriented in the entity's local XY plane, emitting along -Z.
    /// Sized by `area_radius`.
    Disk,
    /// Spherical emitter. Sized by `area_radius`. Always faces the shaded point.
    Sphere,
    /// Capsule-like tube along the entity's local X axis. `area_width` is the
    /// length and `area_radius` is the tube radius.
    Tube,
}

/// Light source component.
///
/// Attach to an entity with a transform to illuminate the scene.
/// The transform's -Z axis defines the light direction (for directional and spot lights).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Light {
    /// The type of light (directional, point, or spot).
    pub light_type: LightType,
    /// Light color as linear RGB.
    pub color: nalgebra_glm::Vec3,
    /// Light intensity (lumens for point/spot, lux for directional).
    pub intensity: f32,
    /// Maximum range for point/spot lights (0 = unlimited).
    pub range: f32,
    /// Inner cone angle in radians for spot lights (full intensity).
    pub inner_cone_angle: f32,
    /// Outer cone angle in radians for spot lights (zero intensity).
    pub outer_cone_angle: f32,
    /// Whether this light casts shadows.
    pub cast_shadows: bool,
    /// Depth bias to reduce shadow acne artifacts.
    pub shadow_bias: f32,
    /// Per-light shadow map resolution. 0 falls back to the renderer default.
    #[serde(default)]
    pub shadow_resolution: u32,
    /// Maximum distance at which this light casts shadows. 0 = unlimited.
    #[serde(default)]
    pub shadow_distance: f32,
    /// Optional cookie texture path (IES profile or projected mask).
    #[serde(default)]
    pub cookie_texture: Option<String>,
    /// Emitter shape for `LightType::Area`. Ignored for other light types.
    #[serde(default)]
    pub area_shape: AreaLightShape,
    /// Width of a rectangular area light, or length of a tube light.
    #[serde(default = "default_area_extent")]
    pub area_width: f32,
    /// Height of a rectangular area light.
    #[serde(default = "default_area_extent")]
    pub area_height: f32,
    /// Radius of a disk, sphere, or tube area light.
    #[serde(default = "default_area_extent")]
    pub area_radius: f32,
    /// Whether a rectangular or disk area light emits from both faces.
    #[serde(default)]
    pub area_two_sided: bool,
    /// Optional emissive texture projected across a rectangular area light.
    #[serde(default)]
    pub area_emissive_texture: Option<String>,
}

fn default_area_extent() -> f32 {
    1.0
}

impl Default for Light {
    fn default() -> Self {
        Self {
            light_type: LightType::default(),
            color: nalgebra_glm::Vec3::new(0.0, 0.0, 0.0),
            intensity: 0.0,
            range: 0.0,
            inner_cone_angle: 0.0,
            outer_cone_angle: 0.0,
            cast_shadows: false,
            shadow_bias: 0.0,
            shadow_resolution: 0,
            shadow_distance: 0.0,
            cookie_texture: None,
            area_shape: AreaLightShape::Rectangle,
            area_width: default_area_extent(),
            area_height: default_area_extent(),
            area_radius: default_area_extent(),
            area_two_sided: false,
            area_emissive_texture: None,
        }
    }
}

impl Light {
    /// Enables shadow casting with the specified depth bias.
    pub fn with_shadows(mut self, bias: f32) -> Self {
        self.cast_shadows = true;
        self.shadow_bias = bias;
        self
    }
}
