use super::DenselySampledSpectrumBuffer;
use shared::core::color::{RGB, RGBToSpectrumTable, XYZ};
use shared::core::geometry::Point2f;
use shared::spectra::RGBColorSpace;
use shared::utils::math::SquareMatrix;
use shared::utils::ptr::Ptr;

pub struct RGBColorSpaceData {
    _illuminant: DenselySampledSpectrumBuffer,
    pub view: RGBColorSpace,
}

impl RGBColorSpaceData {
    pub fn new(
        r: Point2f,
        g: Point2f,
        b: Point2f,
        illuminant: DenselySampledSpectrumBuffer,
        rgb_to_spectrum_table: Ptr<RGBToSpectrumTable>,
    ) -> Self {
        let w_xyz: XYZ = illuminant.to_xyz();
        let w = w_xyz.xy();
        let r_xyz = XYZ::from_xyy(r, Some(1.0));
        let g_xyz = XYZ::from_xyy(g, Some(1.0));
        let b_xyz = XYZ::from_xyy(b, Some(1.0));
        let rgb_values = [
            [r_xyz.x(), g_xyz.x(), b_xyz.x()],
            [r_xyz.y(), g_xyz.y(), b_xyz.y()],
            [r_xyz.z(), g_xyz.z(), b_xyz.z()],
        ];
        let rgb = SquareMatrix::new(rgb_values);
        let c: RGB = rgb.inverse()? * w_xyz;
        let xyz_from_rgb = rgb * SquareMatrix::diag(&[c.r, c.g, c.b]);
        let rgb_from_xyz = xyz_from_rgb
            .inverse()
            .expect("XYZ from RGB matrix is singular");
        let view = RGBColorSpace {
            r,
            g,
            b,
            w,
            illuminant: illuminant.view,
            xyz_from_rgb,
            rgb_from_xyz,
            rgb_to_spectrum_table,
        };
        Self {
            _illuminant: illuminant,
            view,
        }
    }
}
