use crate::spectra::colorspace::RGBColorSpaceData;
use shared::core::color::RGBToSpectrumTable;
use shared::core::geometry::Point2f;
use shared::core::spectrum::Spectrum;
use shared::core::spectrum::StandardSpectra;
use shared::spectra::RGBColorSpace;
use shared::spectra::StandardColorSpaces;
use shared::spectra::cie::{CIE_D65, CIE_X, CIE_Y, CIE_Z};
use std::sync::Arc;
use std::sync::LazyLock;

pub mod colorspace;
pub mod data;
pub mod dense;
pub mod piecewise;

// pub use data;
pub use dense::DenselySampledSpectrumBuffer;

static CIE_X_DATA: LazyLock<DenselySampledSpectrumBuffer> =
    LazyLock::new(|| data::create_cie_buffer(&CIE_X));
static CIE_Y_DATA: LazyLock<DenselySampledSpectrumBuffer> =
    LazyLock::new(|| data::create_cie_buffer(&CIE_Y));
static CIE_Z_DATA: LazyLock<DenselySampledSpectrumBuffer> =
    LazyLock::new(|| data::create_cie_buffer(&CIE_Z));
static CIE_D65_DATA: LazyLock<DenselySampledSpectrumBuffer> =
    LazyLock::new(|| data::create_cie_buffer(&CIE_D65));

pub fn cie_x() -> Spectrum {
    Spectrum::DenselySampled(CIE_X_DATA.view)
}

pub fn cie_y() -> Spectrum {
    Spectrum::DenselySampled(CIE_Y_DATA.view)
}

pub fn cie_z() -> Spectrum {
    Spectrum::DenselySampled(CIE_Z_DATA.view)
}

pub fn cie_d65() -> Spectrum {
    Spectrum::DenselySampled(CIE_D65_DATA.view)
}

pub fn get_spectra_context() -> StandardSpectra {
    StandardSpectra {
        x: CIE_X_DATA.view,
        y: CIE_Y_DATA.view,
        z: CIE_Z_DATA.view,
        d65: CIE_D65_DATA.view,
    }
}

pub static SRGB: LazyLock<RGBColorSpaceData> = LazyLock::new(|| {
    let illum = DenselySampledSpectrumBuffer::new(
        CIE_D65_DATA.view.lambda_min,
        CIE_D65_DATA.view.lambda_max,
        CIE_D65_DATA._storage.clone(),
    );

    RGBColorSpaceData::new(
        Point2f::new(0.64, 0.33),
        Point2f::new(0.3, 0.6),
        Point2f::new(0.15, 0.06),
        illum,
        RGBToSpectrumTable::srgb(),
    )
});

pub static DCI_P3: LazyLock<RGBColorSpaceData> = LazyLock::new(|| {
    let illum = DenselySampledSpectrumBuffer::new(
        CIE_D65_DATA.view.lambda_min,
        CIE_D65_DATA.view.lambda_max,
        CIE_D65_DATA._storage.clone(),
    );

    let r = Point2f::new(0.680, 0.320);
    let g = Point2f::new(0.265, 0.690);
    let b = Point2f::new(0.150, 0.060);

    RGBColorSpaceData::new(r, g, b, illum, RGBToSpectrumTable)
});

pub static REC2020: LazyLock<Arc<RGBColorSpace>> = LazyLock::new(|| {
    let illum = DenselySampledSpectrumBuffer::new(
        CIE_D65_DATA.view.lambda_min,
        CIE_D65_DATA.view.lambda_max,
        CIE_D65_DATA._storage.clone(),
    );

    let r = Point2f::new(0.708, 0.292);
    let g = Point2f::new(0.170, 0.797);
    let b = Point2f::new(0.131, 0.046);

    let table = RGBToSpectrumTable::rec2020();

    RGBColorSpace::new(r, g, b, illum, table)
});

pub static ACES: LazyLock<Arc<RGBColorSpace>> = LazyLock::new(|| {
    let r = Point2f::new(0.7347, 0.2653);
    let g = Point2f::new(0.0000, 1.0000);
    let b = Point2f::new(0.0001, -0.0770);
    let illuminant = Spectrum::std_illuminant_d65();

    let table = RGBToSpectrumTable::aces2065_1();

    RGBColorSpaceData::new(r, g, b, illuminant, table)
});

pub fn get_colorspace_context() -> StandardColorSpaces {
    StandardColorSpaces {
        srgb: SRGB,
        dci_p3: DCI_P3,
        rec2020: REC2020,
        aces2065_1: ACES,
    }
}
