use shared::core::spectrum::Spectrum;
use shared::spectra::cie::*;
use shared::spectra::{DenselySampledSpectrum, PiecewiseLinearSpectrum};
use shared::{gbox, leak, Float, Ptr};
use std::collections::HashMap;
use std::sync::LazyLock;

pub fn create_cie(data: &[Float]) -> DenselySampledSpectrum {
    let (start_lambda, step) = match data.len() {
        471 => (360.0, 1.0),
        95 => (300.0, 5.0),
        n => panic!("Unexpected CIE data length: {}", n),
    };

    let lambdas: Vec<Float> = (0..data.len())
        .map(|i| start_lambda + i as Float * step)
        .collect();

    let buffer = PiecewiseLinearSpectrum::new(lambdas, data.to_vec());
    let spec = Spectrum::Piecewise(Ptr::from(&*buffer));
    DenselySampledSpectrum::from_spectrum(&spec)
}

pub static NAMED_SPECTRA: LazyLock<HashMap<String, Spectrum>> = LazyLock::new(|| {
    let mut m = HashMap::new();

    macro_rules! add {
        ($name:expr, $data:expr, $norm:expr) => {
            let buffer = PiecewiseLinearSpectrum::from_interleaved($data, $norm);
            let spectrum = Spectrum::Piecewise(leak(buffer));
            m.insert($name.to_string(), spectrum);
        };
    }

    add!("stdillum-A", &CIE_ILLUM_A, true);
    add!("stdillum-D50", &CIE_ILLUM_D5000, true);
    add!("stdillum-D65", &CIE_ILLUM_D6500, true);
    add!("stdillum-F1", &CIE_ILLUM_F1, true);
    add!("stdillum-F2", &CIE_ILLUM_F2, true);
    add!("stdillum-F3", &CIE_ILLUM_F3, true);
    add!("stdillum-F4", &CIE_ILLUM_F4, true);
    add!("stdillum-F5", &CIE_ILLUM_F5, true);
    add!("stdillum-F6", &CIE_ILLUM_F6, true);
    add!("stdillum-F7", &CIE_ILLUM_F7, true);
    add!("stdillum-F8", &CIE_ILLUM_F8, true);
    add!("stdillum-F9", &CIE_ILLUM_F9, true);
    add!("stdillum-F10", &CIE_ILLUM_F10, true);
    add!("stdillum-F11", &CIE_ILLUM_F11, true);
    add!("stdillum-F12", &CIE_ILLUM_F12, true);
    add!("illum-acesD60", &ACES_ILLUM_D60, true);

    add!("glass-BK7", &GLASS_BK7_ETA, false);
    add!("glass-BAF10", &GLASS_BAF10_ETA, false);
    add!("glass-FK51A", &GLASS_FK51A_ETA, false);
    add!("glass-LASF9", &GLASS_LASF9_ETA, false);
    add!("glass-F5", &GLASS_SF5_ETA, false);
    add!("glass-F10", &GLASS_SF10_ETA, false);
    add!("glass-F11", &GLASS_SF11_ETA, false);

    add!("metal-Ag-eta", &AG_ETA, false);
    add!("metal-Ag-k", &AG_K, false);
    add!("metal-Al-eta", &AL_ETA, false);
    add!("metal-Al-k", &AL_K, false);
    add!("metal-Au-eta", &AU_ETA, false);
    add!("metal-Au-k", &AU_K, false);
    add!("metal-Cu-eta", &CU_ETA, false);
    add!("metal-Cu-k", &CU_K, false);
    add!("metal-CuZn-eta", &CUZN_ETA, false);
    add!("metal-CuZn-k", &CUZN_K, false);
    add!("metal-MgO-eta", &MGO_ETA, false);
    add!("metal-MgO-k", &MGO_K, false);
    add!("metal-TiO2-eta", &TIO2_ETA, false);
    add!("metal-TiO2-k", &TIO2_K, false);

    add!("canon_eos_100d_r", &CANON_EOS_100D_R, false);
    add!("canon_eos_100d_g", &CANON_EOS_100D_G, false);
    add!("canon_eos_100d_b", &CANON_EOS_100D_B, false);

    add!("canon_eos_1dx_mkii_r", &CANON_EOS_1DX_MKII_R, false);
    add!("canon_eos_1dx_mkii_g", &CANON_EOS_1DX_MKII_G, false);
    add!("canon_eos_1dx_mkii_b", &CANON_EOS_1DX_MKII_B, false);

    add!("canon_eos_200d_r", &CANON_EOS_200D_R, false);
    add!("canon_eos_200d_g", &CANON_EOS_200D_G, false);
    add!("canon_eos_200d_b", &CANON_EOS_200D_B, false);

    add!("canon_eos_200d_mkii_r", &CANON_EOS_200D_MKII_R, false);
    add!("canon_eos_200d_mkii_g", &CANON_EOS_200D_MKII_G, false);
    add!("canon_eos_200d_mkii_b", &CANON_EOS_200D_MKII_B, false);

    add!("canon_eos_5d_r", &CANON_EOS_5D_R, false);
    add!("canon_eos_5d_g", &CANON_EOS_5D_G, false);
    add!("canon_eos_5d_b", &CANON_EOS_5D_B, false);

    add!("canon_eos_5d_mkii_r", &CANON_EOS_5D_MKII_R, false);
    add!("canon_eos_5d_mkii_g", &CANON_EOS_5D_MKII_G, false);
    add!("canon_eos_5d_mkii_b", &CANON_EOS_5D_MKII_B, false);

    add!("canon_eos_5d_mkiii_r", &CANON_EOS_5D_MKIII_R, false);
    add!("canon_eos_5d_mkiii_g", &CANON_EOS_5D_MKIII_G, false);
    add!("canon_eos_5d_mkiii_b", &CANON_EOS_5D_MKIII_B, false);

    add!("canon_eos_5d_mkiv_r", &CANON_EOS_5D_MKIV_R, false);
    add!("canon_eos_5d_mkiv_g", &CANON_EOS_5D_MKIV_G, false);
    add!("canon_eos_5d_mkiv_b", &CANON_EOS_5D_MKIV_B, false);

    add!("canon_eos_5ds_r", &CANON_EOS_5DS_R, false);
    add!("canon_eos_5ds_g", &CANON_EOS_5DS_G, false);
    add!("canon_eos_5ds_b", &CANON_EOS_5DS_B, false);

    add!("canon_eos_m_r", &CANON_EOS_M_R, false);
    add!("canon_eos_m_g", &CANON_EOS_M_G, false);
    add!("canon_eos_m_b", &CANON_EOS_M_B, false);

    add!("hasselblad_l1d_20c_r", &HASSELBLAD_L1D_20C_R, false);
    add!("hasselblad_l1d_20c_g", &HASSELBLAD_L1D_20C_G, false);
    add!("hasselblad_l1d_20c_b", &HASSELBLAD_L1D_20C_B, false);

    add!("nikon_d810_r", &NIKON_D810_R, false);
    add!("nikon_d810_g", &NIKON_D810_G, false);
    add!("nikon_d810_b", &NIKON_D810_B, false);

    add!("nikon_d850_r", &NIKON_D850_R, false);
    add!("nikon_d850_g", &NIKON_D850_G, false);
    add!("nikon_d850_b", &NIKON_D850_B, false);

    add!("sony_ilce_6400_r", &SONY_ILCE_6400_R, false);
    add!("sony_ilce_6400_g", &SONY_ILCE_6400_G, false);
    add!("sony_ilce_6400_b", &SONY_ILCE_6400_B, false);

    add!("sony_ilce_7m3_r", &SONY_ILCE_7M3_R, false);
    add!("sony_ilce_7m3_g", &SONY_ILCE_7M3_G, false);
    add!("sony_ilce_7m3_b", &SONY_ILCE_7M3_B, false);

    add!("sony_ilce_7rm3_r", &SONY_ILCE_7RM3_R, false);
    add!("sony_ilce_7rm3_g", &SONY_ILCE_7RM3_G, false);
    add!("sony_ilce_7rm3_b", &SONY_ILCE_7RM3_B, false);

    add!("sony_ilce_9_r", &SONY_ILCE_9_R, false);
    add!("sony_ilce_9_g", &SONY_ILCE_9_G, false);
    add!("sony_ilce_9_b", &SONY_ILCE_9_B, false);

    m
});

pub fn get_named_spectrum(name: &str) -> Option<Spectrum> {
    NAMED_SPECTRA.get(name).copied()
}
