use {
    crate::{
        gfx_apis::gl::sys::{GL_BGRA_EXT, GL_RGBA, GL_RGBA8, GL_UNSIGNED_BYTE, GLenum, GLint},
        pipewire::pw_pod::{
            SPA_VIDEO_FORMAT_ABGR_210LE, SPA_VIDEO_FORMAT_ARGB_210LE, SPA_VIDEO_FORMAT_BGR,
            SPA_VIDEO_FORMAT_BGR15, SPA_VIDEO_FORMAT_BGR16, SPA_VIDEO_FORMAT_BGRA,
            SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_GRAY8, SPA_VIDEO_FORMAT_RGB,
            SPA_VIDEO_FORMAT_RGB16, SPA_VIDEO_FORMAT_RGBA, SPA_VIDEO_FORMAT_RGBx,
            SPA_VIDEO_FORMAT_UNKNOWN, SPA_VIDEO_FORMAT_xBGR_210LE, SPA_VIDEO_FORMAT_xRGB_210LE,
            SpaVideoFormat,
        },
    },
    ahash::AHashMap,
    ash::vk,
    jay_config::video::Format as ConfigFormat,
    std::{
        fmt::{self, Debug, Write},
        sync::LazyLock,
    },
};

#[derive(Copy, Clone, Debug)]
pub struct FormatShmInfo {
    pub gl_format: GLint,
    pub gl_internal_format: GLenum,
    pub gl_type: GLint,
}

#[derive(Copy, Clone, Debug)]
pub struct Format {
    pub name: &'static str,
    pub vk_format: vk::Format,
    pub drm: u32,
    pub wl_id: Option<u32>,
    pub external_only_guess: bool,
    pub has_alpha: bool,
    pub pipewire: SpaVideoFormat,
    pub opaque: Option<&'static Format>,
    pub shm_info: Option<FormatShmInfo>,
    pub config: ConfigFormat,
    pub bpp: u32,
}

const fn default(config: ConfigFormat) -> Format {
    Format {
        name: "",
        vk_format: vk::Format::UNDEFINED,
        drm: 0,
        wl_id: None,
        external_only_guess: false,
        has_alpha: false,
        pipewire: SPA_VIDEO_FORMAT_UNKNOWN,
        opaque: None,
        shm_info: None,
        config,
        bpp: 4,
    }
}

impl PartialEq for Format {
    fn eq(&self, other: &Self) -> bool {
        self.drm == other.drm
    }
}

impl Eq for Format {}

static FORMATS_MAP: LazyLock<AHashMap<u32, &'static Format>> = LazyLock::new(|| {
    let mut map = AHashMap::new();
    for format in FORMATS {
        assert!(map.insert(format.drm, format).is_none());
    }
    map
});

static PW_FORMATS_MAP: LazyLock<AHashMap<SpaVideoFormat, &'static Format>> = LazyLock::new(|| {
    let mut map = AHashMap::new();
    for format in FORMATS {
        if format.pipewire != SPA_VIDEO_FORMAT_UNKNOWN {
            assert!(map.insert(format.pipewire, format).is_none());
        }
    }
    map
});

static FORMATS_REFS: LazyLock<Vec<&'static Format>> = LazyLock::new(|| FORMATS.iter().collect());

static FORMATS_NAMES: LazyLock<AHashMap<&'static str, &'static Format>> = LazyLock::new(|| {
    let mut map = AHashMap::new();
    for format in FORMATS {
        assert!(map.insert(format.name, format).is_none());
    }
    map
});

static FORMATS_CONFIG: LazyLock<AHashMap<ConfigFormat, &'static Format>> = LazyLock::new(|| {
    let mut map = AHashMap::new();
    for format in FORMATS {
        assert!(map.insert(format.config, format).is_none());
    }
    map
});

#[test]
fn formats_dont_panic() {
    formats();
    pw_formats();
    named_formats();
    config_formats();
}

pub fn formats() -> &'static AHashMap<u32, &'static Format> {
    &FORMATS_MAP
}

pub fn pw_formats() -> &'static AHashMap<SpaVideoFormat, &'static Format> {
    &PW_FORMATS_MAP
}

pub fn ref_formats() -> &'static [&'static Format] {
    &FORMATS_REFS
}

pub fn named_formats() -> &'static AHashMap<&'static str, &'static Format> {
    &FORMATS_NAMES
}

pub fn config_formats() -> &'static AHashMap<ConfigFormat, &'static Format> {
    &FORMATS_CONFIG
}

const fn fourcc_code(a: char, b: char, c: char, d: char) -> u32 {
    (a as u32) | ((b as u32) << 8) | ((c as u32) << 16) | ((d as u32) << 24)
}

#[expect(dead_code)]
pub fn debug(fourcc: u32) -> impl Debug {
    fmt::from_fn(move |fmt| {
        fmt.write_char(fourcc as u8 as char)?;
        fmt.write_char((fourcc >> 8) as u8 as char)?;
        fmt.write_char((fourcc >> 16) as u8 as char)?;
        fmt.write_char((fourcc >> 24) as u8 as char)?;
        Ok(())
    })
}

const ARGB8888_ID: u32 = 0;
const ARGB8888_DRM: u32 = fourcc_code('A', 'R', '2', '4');

const XRGB8888_ID: u32 = 1;
const XRGB8888_DRM: u32 = fourcc_code('X', 'R', '2', '4');

pub fn map_wayland_format_id(id: u32) -> u32 {
    match id {
        ARGB8888_ID => ARGB8888_DRM,
        XRGB8888_ID => XRGB8888_DRM,
        _ => id,
    }
}

pub static ARGB8888: &Format = &Format {
    name: "argb8888",
    shm_info: Some(FormatShmInfo {
        gl_format: GL_BGRA_EXT,
        gl_internal_format: GL_RGBA8,
        gl_type: GL_UNSIGNED_BYTE,
    }),
    vk_format: vk::Format::B8G8R8A8_UNORM,
    bpp: 4,
    drm: ARGB8888_DRM,
    wl_id: Some(ARGB8888_ID),
    external_only_guess: false,
    has_alpha: true,
    pipewire: SPA_VIDEO_FORMAT_BGRA,
    opaque: Some(XRGB8888),
    config: ConfigFormat::ARGB8888,
};

pub static XRGB8888: &Format = &Format {
    name: "xrgb8888",
    shm_info: Some(FormatShmInfo {
        gl_format: GL_BGRA_EXT,
        gl_internal_format: GL_RGBA8,
        gl_type: GL_UNSIGNED_BYTE,
    }),
    vk_format: vk::Format::B8G8R8A8_UNORM,
    bpp: 4,
    drm: XRGB8888_DRM,
    wl_id: Some(XRGB8888_ID),
    external_only_guess: false,
    has_alpha: false,
    pipewire: SPA_VIDEO_FORMAT_BGRx,
    opaque: None,
    config: ConfigFormat::XRGB8888,
};

static ABGR8888: &Format = &Format {
    name: "abgr8888",
    shm_info: Some(FormatShmInfo {
        gl_format: GL_RGBA,
        gl_internal_format: GL_RGBA8,
        gl_type: GL_UNSIGNED_BYTE,
    }),
    vk_format: vk::Format::R8G8B8A8_UNORM,
    bpp: 4,
    drm: fourcc_code('A', 'B', '2', '4'),
    wl_id: None,
    external_only_guess: false,
    has_alpha: true,
    pipewire: SPA_VIDEO_FORMAT_RGBA,
    opaque: Some(XBGR8888),
    config: ConfigFormat::ABGR8888,
};

static XBGR8888: &Format = &Format {
    name: "xbgr8888",
    shm_info: Some(FormatShmInfo {
        gl_format: GL_RGBA,
        gl_internal_format: GL_RGBA8,
        gl_type: GL_UNSIGNED_BYTE,
    }),
    vk_format: vk::Format::R8G8B8A8_UNORM,
    bpp: 4,
    drm: fourcc_code('X', 'B', '2', '4'),
    wl_id: None,
    external_only_guess: false,
    has_alpha: false,
    pipewire: SPA_VIDEO_FORMAT_RGBx,
    opaque: None,
    config: ConfigFormat::XBGR8888,
};

static R8: &Format = &Format {
    name: "r8",
    vk_format: vk::Format::R8_UNORM,
    bpp: 1,
    drm: fourcc_code('R', '8', ' ', ' '),
    pipewire: SPA_VIDEO_FORMAT_GRAY8,
    ..default(ConfigFormat::R8)
};

static GR88: &Format = &Format {
    name: "gr88",
    vk_format: vk::Format::R8G8_UNORM,
    bpp: 2,
    drm: fourcc_code('G', 'R', '8', '8'),
    ..default(ConfigFormat::GR88)
};

static RGB888: &Format = &Format {
    name: "rgb888",
    vk_format: vk::Format::B8G8R8_UNORM,
    bpp: 3,
    drm: fourcc_code('R', 'G', '2', '4'),
    pipewire: SPA_VIDEO_FORMAT_BGR,
    ..default(ConfigFormat::RGB888)
};

static BGR888: &Format = &Format {
    name: "bgr888",
    vk_format: vk::Format::R8G8B8_UNORM,
    bpp: 3,
    drm: fourcc_code('B', 'G', '2', '4'),
    pipewire: SPA_VIDEO_FORMAT_RGB,
    ..default(ConfigFormat::BGR888)
};

static RGBA4444: &Format = &Format {
    name: "rgba4444",
    vk_format: vk::Format::R4G4B4A4_UNORM_PACK16,
    bpp: 2,
    drm: fourcc_code('R', 'A', '1', '2'),
    has_alpha: true,
    opaque: Some(RGBX4444),
    ..default(ConfigFormat::RGBA4444)
};

static RGBX4444: &Format = &Format {
    name: "rgbx4444",
    vk_format: vk::Format::R4G4B4A4_UNORM_PACK16,
    bpp: 2,
    drm: fourcc_code('R', 'X', '1', '2'),
    ..default(ConfigFormat::RGBX4444)
};

static BGRA4444: &Format = &Format {
    name: "bgra4444",
    vk_format: vk::Format::B4G4R4A4_UNORM_PACK16,
    bpp: 2,
    drm: fourcc_code('B', 'A', '1', '2'),
    has_alpha: true,
    opaque: Some(BGRX4444),
    ..default(ConfigFormat::BGRA4444)
};

static BGRX4444: &Format = &Format {
    name: "bgrx4444",
    vk_format: vk::Format::B4G4R4A4_UNORM_PACK16,
    bpp: 2,
    drm: fourcc_code('B', 'X', '1', '2'),
    ..default(ConfigFormat::BGRX4444)
};

static RGB565: &Format = &Format {
    name: "rgb565",
    vk_format: vk::Format::R5G6B5_UNORM_PACK16,
    bpp: 2,
    drm: fourcc_code('R', 'G', '1', '6'),
    pipewire: SPA_VIDEO_FORMAT_BGR16,
    ..default(ConfigFormat::RGB565)
};

static BGR565: &Format = &Format {
    name: "bgr565",
    vk_format: vk::Format::B5G6R5_UNORM_PACK16,
    bpp: 2,
    drm: fourcc_code('B', 'G', '1', '6'),
    pipewire: SPA_VIDEO_FORMAT_RGB16,
    ..default(ConfigFormat::BGR565)
};

static RGBA5551: &Format = &Format {
    name: "rgba5551",
    vk_format: vk::Format::R5G5B5A1_UNORM_PACK16,
    bpp: 2,
    drm: fourcc_code('R', 'A', '1', '5'),
    has_alpha: true,
    opaque: Some(RGBX5551),
    ..default(ConfigFormat::RGBA5551)
};

static RGBX5551: &Format = &Format {
    name: "rgbx5551",
    vk_format: vk::Format::R5G5B5A1_UNORM_PACK16,
    bpp: 2,
    drm: fourcc_code('R', 'X', '1', '5'),
    ..default(ConfigFormat::RGBX5551)
};

static BGRA5551: &Format = &Format {
    name: "bgra5551",
    vk_format: vk::Format::B5G5R5A1_UNORM_PACK16,
    bpp: 2,
    drm: fourcc_code('B', 'A', '1', '5'),
    has_alpha: true,
    opaque: Some(BGRX5551),
    ..default(ConfigFormat::BGRA5551)
};

static BGRX5551: &Format = &Format {
    name: "bgrx5551",
    vk_format: vk::Format::B5G5R5A1_UNORM_PACK16,
    bpp: 2,
    drm: fourcc_code('B', 'X', '1', '5'),
    ..default(ConfigFormat::BGRX5551)
};

static ARGB1555: &Format = &Format {
    name: "argb1555",
    vk_format: vk::Format::A1R5G5B5_UNORM_PACK16,
    bpp: 2,
    drm: fourcc_code('A', 'R', '1', '5'),
    has_alpha: true,
    opaque: Some(XRGB1555),
    ..default(ConfigFormat::ARGB1555)
};

static XRGB1555: &Format = &Format {
    name: "xrgb1555",
    vk_format: vk::Format::A1R5G5B5_UNORM_PACK16,
    bpp: 2,
    drm: fourcc_code('X', 'R', '1', '5'),
    pipewire: SPA_VIDEO_FORMAT_BGR15,
    ..default(ConfigFormat::XRGB1555)
};

static ARGB2101010: &Format = &Format {
    name: "argb2101010",
    vk_format: vk::Format::A2R10G10B10_UNORM_PACK32,
    bpp: 4,
    drm: fourcc_code('A', 'R', '3', '0'),
    has_alpha: true,
    opaque: Some(XRGB2101010),
    pipewire: SPA_VIDEO_FORMAT_ARGB_210LE,
    ..default(ConfigFormat::ARGB2101010)
};

static XRGB2101010: &Format = &Format {
    name: "xrgb2101010",
    vk_format: vk::Format::A2R10G10B10_UNORM_PACK32,
    bpp: 4,
    drm: fourcc_code('X', 'R', '3', '0'),
    pipewire: SPA_VIDEO_FORMAT_xRGB_210LE,
    ..default(ConfigFormat::XRGB2101010)
};

static ABGR2101010: &Format = &Format {
    name: "abgr2101010",
    vk_format: vk::Format::A2B10G10R10_UNORM_PACK32,
    bpp: 4,
    drm: fourcc_code('A', 'B', '3', '0'),
    has_alpha: true,
    opaque: Some(XBGR2101010),
    pipewire: SPA_VIDEO_FORMAT_ABGR_210LE,
    ..default(ConfigFormat::ABGR2101010)
};

static XBGR2101010: &Format = &Format {
    name: "xbgr2101010",
    vk_format: vk::Format::A2B10G10R10_UNORM_PACK32,
    bpp: 4,
    drm: fourcc_code('X', 'B', '3', '0'),
    pipewire: SPA_VIDEO_FORMAT_xBGR_210LE,
    ..default(ConfigFormat::XBGR2101010)
};

static ABGR16161616: &Format = &Format {
    name: "abgr16161616",
    vk_format: vk::Format::R16G16B16A16_UNORM,
    bpp: 8,
    drm: fourcc_code('A', 'B', '4', '8'),
    has_alpha: true,
    opaque: Some(XBGR16161616),
    ..default(ConfigFormat::ABGR16161616)
};

static XBGR16161616: &Format = &Format {
    name: "xbgr16161616",
    vk_format: vk::Format::R16G16B16A16_UNORM,
    bpp: 8,
    drm: fourcc_code('X', 'B', '4', '8'),
    ..default(ConfigFormat::XBGR16161616)
};

pub static ABGR16161616F: &Format = &Format {
    name: "abgr16161616f",
    vk_format: vk::Format::R16G16B16A16_SFLOAT,
    bpp: 8,
    drm: fourcc_code('A', 'B', '4', 'H'),
    has_alpha: true,
    opaque: Some(XBGR16161616F),
    ..default(ConfigFormat::ABGR16161616F)
};

static XBGR16161616F: &Format = &Format {
    name: "xbgr16161616f",
    vk_format: vk::Format::R16G16B16A16_SFLOAT,
    bpp: 8,
    drm: fourcc_code('X', 'B', '4', 'H'),
    ..default(ConfigFormat::XBGR16161616F)
};

static BGR161616: &Format = &Format {
    name: "bgr161616",
    vk_format: vk::Format::R16G16B16_UNORM,
    bpp: 6,
    drm: fourcc_code('B', 'G', '4', '8'),
    ..default(ConfigFormat::BGR161616)
};

static R16F: &Format = &Format {
    name: "r16f",
    vk_format: vk::Format::R16_SFLOAT,
    bpp: 2,
    drm: fourcc_code('R', ' ', ' ', 'H'),
    ..default(ConfigFormat::R16F)
};

static GR1616F: &Format = &Format {
    name: "gr1616f",
    vk_format: vk::Format::R16G16_SFLOAT,
    bpp: 4,
    drm: fourcc_code('G', 'R', ' ', 'H'),
    ..default(ConfigFormat::GR1616F)
};

static BGR161616F: &Format = &Format {
    name: "bgr161616f",
    vk_format: vk::Format::R16G16B16_SFLOAT,
    bpp: 6,
    drm: fourcc_code('B', 'G', 'R', 'H'),
    ..default(ConfigFormat::BGR161616F)
};

static R32F: &Format = &Format {
    name: "r32f",
    vk_format: vk::Format::R32_SFLOAT,
    bpp: 4,
    drm: fourcc_code('R', ' ', ' ', 'F'),
    ..default(ConfigFormat::R32F)
};

static GR3232F: &Format = &Format {
    name: "gr3232f",
    vk_format: vk::Format::R32G32_SFLOAT,
    bpp: 8,
    drm: fourcc_code('G', 'R', ' ', 'F'),
    ..default(ConfigFormat::GR3232F)
};

static BGR323232F: &Format = &Format {
    name: "bgr323232f",
    vk_format: vk::Format::R32G32B32_SFLOAT,
    bpp: 12,
    drm: fourcc_code('B', 'G', 'R', 'F'),
    ..default(ConfigFormat::BGR323232F)
};

static ABGR32323232F: &Format = &Format {
    name: "abgr32323232f",
    vk_format: vk::Format::R32G32B32A32_SFLOAT,
    bpp: 16,
    drm: fourcc_code('A', 'B', '8', 'F'),
    has_alpha: true,
    ..default(ConfigFormat::ABGR32323232F)
};

pub static FORMATS: &[Format] = &[
    *ARGB8888,
    *XRGB8888,
    *ABGR8888,
    *XBGR8888,
    *R8,
    *GR88,
    *RGB888,
    *BGR888,
    #[cfg(target_endian = "little")]
    *RGBA4444,
    #[cfg(target_endian = "little")]
    *RGBX4444,
    #[cfg(target_endian = "little")]
    *BGRA4444,
    #[cfg(target_endian = "little")]
    *BGRX4444,
    #[cfg(target_endian = "little")]
    *RGB565,
    #[cfg(target_endian = "little")]
    *BGR565,
    #[cfg(target_endian = "little")]
    *RGBA5551,
    #[cfg(target_endian = "little")]
    *RGBX5551,
    #[cfg(target_endian = "little")]
    *BGRA5551,
    #[cfg(target_endian = "little")]
    *BGRX5551,
    #[cfg(target_endian = "little")]
    *ARGB1555,
    #[cfg(target_endian = "little")]
    *XRGB1555,
    #[cfg(target_endian = "little")]
    *ARGB2101010,
    #[cfg(target_endian = "little")]
    *XRGB2101010,
    #[cfg(target_endian = "little")]
    *ABGR2101010,
    #[cfg(target_endian = "little")]
    *XBGR2101010,
    #[cfg(target_endian = "little")]
    *ABGR16161616,
    #[cfg(target_endian = "little")]
    *XBGR16161616,
    #[cfg(target_endian = "little")]
    *ABGR16161616F,
    #[cfg(target_endian = "little")]
    *XBGR16161616F,
    #[cfg(target_endian = "little")]
    *BGR161616,
    #[cfg(target_endian = "little")]
    *R16F,
    #[cfg(target_endian = "little")]
    *GR1616F,
    #[cfg(target_endian = "little")]
    *BGR161616F,
    #[cfg(target_endian = "little")]
    *R32F,
    #[cfg(target_endian = "little")]
    *GR3232F,
    #[cfg(target_endian = "little")]
    *BGR323232F,
    #[cfg(target_endian = "little")]
    *ABGR32323232F,
];
