use std::fmt;

/// Represents a color in the RGB (Red, Green, Blue) model.
/// Values range from 0 to 255.
pub struct Rgb {
    pub r: u8,
    pub g: u8,
    pub b: u8,
}

/// Represents a color in the HSV (Hue, Saturation, Value) model.
/// - `h` (hue): 0-359 degrees
/// - `s` (saturation): 0.0-1.0
/// - `v` (value/brightness): 0.0-1.0
pub struct Hsv {
    pub h: u16,
    pub s: f32,
    pub v: f32,
}

// Implement the `Debug` trait for Rgb to allow pretty-printing.
impl fmt::Debug for Rgb {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Rgb({}, {}, {})", self.r, self.g, self.b)
    }
}


/// Provides the conversion logic from HSV to RGB.
/// This uses the standard mathematical formula for the conversion.
impl From<Hsv> for Rgb {
    fn from(hsv: Hsv) -> Self {
        // Ensure saturation and value are within the valid range [0.0, 1.0]
        let s = hsv.s.clamp(0.0, 1.0);
        let v = hsv.v.clamp(0.0, 1.0);
        
        // When saturation is 0, the color is a shade of gray.
        if s == 0.0 {
            let val = (v * 255.0) as u8;
            return Rgb { r: val, g: val, b: val };
        }

        // The hue is treated as a sector on a color wheel.
        let h = hsv.h as f32 / 60.0; // Sector 0-5
        let i = h.floor() as i32;
        let f = h - i as f32; // Fractional part of h

        let p = v * (1.0 - s);
        let q = v * (1.0 - f * s);
        let t = v * (1.0 - (1.0 - f) * s);

        // Determine the RGB values based on the hue sector.
        let (r, g, b) = match i {
            0 => (v, t, p),
            1 => (q, v, p),
            2 => (p, v, t),
            3 => (p, q, v),
            4 => (t, p, v),
            _ => (v, p, q), // Default case for sector 5
        };

        // Convert the float RGB values (0.0-1.0) to u8 values (0-255).
        Rgb {
            r: (r * 255.0).round() as u8,
            g: (g * 255.0).round() as u8,
            b: (b * 255.0).round() as u8,
        }
    }
}
