use super::*;
use std::vec;

// ---- Rgb565Frame -----------------------------------------------------------

#[test]
fn rgb565_frame_try_new_accepts_valid_tight() {
  let buf = vec![0u8; 16 * 2 * 4];
  Rgb565Frame::try_new(&buf, 16, 4, 32).expect("valid tight stride");
}

#[test]
fn rgb565_frame_try_new_rejects_zero_dimension() {
  let buf = vec![0u8; 32];
  assert!(matches!(
    Rgb565Frame::try_new(&buf, 0, 0, 0),
    Err(LegacyRgbFrameError::ZeroDimension(_))
  ));
}

#[test]
fn rgb565_frame_try_new_rejects_width_overflow() {
  let buf = vec![0u8; 4];
  let w = u32::MAX / 2 + 1;
  assert!(matches!(
    Rgb565Frame::try_new(&buf, w, 1, w),
    Err(LegacyRgbFrameError::WidthOverflow(_))
  ));
}

#[test]
fn rgb565_frame_try_new_rejects_stride_too_small() {
  let buf = vec![0u8; 16 * 2 * 4];
  // min stride = 2*16 = 32; supply 31
  assert!(matches!(
    Rgb565Frame::try_new(&buf, 16, 4, 31),
    Err(LegacyRgbFrameError::InsufficientStride(_))
  ));
}

#[cfg(target_pointer_width = "32")]
#[test]
fn rgb565_frame_try_new_rejects_geometry_overflow() {
  // Only meaningful on 32-bit targets where `stride * height` as `usize` can overflow.
  // stride=0x1_0000, height=0x1_0000 → product = 2^32 → overflows 32-bit usize.
  let buf: [u8; 0] = [];
  assert!(matches!(
    Rgb565Frame::try_new(&buf, 1, 0x1_0000, 0x1_0000),
    Err(LegacyRgbFrameError::GeometryOverflow(_))
  ));
}

#[test]
fn rgb565_frame_try_new_rejects_plane_too_short() {
  // Valid geometry: 16 px wide, 4 rows, stride=32 → need 128 bytes; give 127
  let buf = vec![0u8; 127];
  assert!(matches!(
    Rgb565Frame::try_new(&buf, 16, 4, 32),
    Err(LegacyRgbFrameError::InsufficientPlane(_))
  ));
}

// ---- Bgr565Frame -----------------------------------------------------------

#[test]
fn bgr565_frame_try_new_accepts_valid_tight() {
  let buf = vec![0u8; 16 * 2 * 4];
  Bgr565Frame::try_new(&buf, 16, 4, 32).expect("valid tight stride");
}

#[test]
fn bgr565_frame_try_new_rejects_zero_dimension() {
  let buf = vec![0u8; 32];
  assert!(matches!(
    Bgr565Frame::try_new(&buf, 0, 0, 0),
    Err(LegacyRgbFrameError::ZeroDimension(_))
  ));
}

#[test]
fn bgr565_frame_try_new_rejects_width_overflow() {
  let buf = vec![0u8; 4];
  let w = u32::MAX / 2 + 1;
  assert!(matches!(
    Bgr565Frame::try_new(&buf, w, 1, w),
    Err(LegacyRgbFrameError::WidthOverflow(_))
  ));
}

#[test]
fn bgr565_frame_try_new_rejects_stride_too_small() {
  let buf = vec![0u8; 16 * 2 * 4];
  assert!(matches!(
    Bgr565Frame::try_new(&buf, 16, 4, 31),
    Err(LegacyRgbFrameError::InsufficientStride(_))
  ));
}

#[cfg(target_pointer_width = "32")]
#[test]
fn bgr565_frame_try_new_rejects_geometry_overflow() {
  let buf: [u8; 0] = [];
  assert!(matches!(
    Bgr565Frame::try_new(&buf, 1, 0x1_0000, 0x1_0000),
    Err(LegacyRgbFrameError::GeometryOverflow(_))
  ));
}

#[test]
fn bgr565_frame_try_new_rejects_plane_too_short() {
  let buf = vec![0u8; 127];
  assert!(matches!(
    Bgr565Frame::try_new(&buf, 16, 4, 32),
    Err(LegacyRgbFrameError::InsufficientPlane(_))
  ));
}

// ---- Rgb555Frame -----------------------------------------------------------

#[test]
fn rgb555_frame_try_new_accepts_valid_tight() {
  let buf = vec![0u8; 16 * 2 * 4];
  Rgb555Frame::try_new(&buf, 16, 4, 32).expect("valid tight stride");
}

#[test]
fn rgb555_frame_try_new_rejects_zero_dimension() {
  let buf = vec![0u8; 32];
  assert!(matches!(
    Rgb555Frame::try_new(&buf, 0, 0, 0),
    Err(LegacyRgbFrameError::ZeroDimension(_))
  ));
}

#[test]
fn rgb555_frame_try_new_rejects_width_overflow() {
  let buf = vec![0u8; 4];
  let w = u32::MAX / 2 + 1;
  assert!(matches!(
    Rgb555Frame::try_new(&buf, w, 1, w),
    Err(LegacyRgbFrameError::WidthOverflow(_))
  ));
}

#[test]
fn rgb555_frame_try_new_rejects_stride_too_small() {
  let buf = vec![0u8; 16 * 2 * 4];
  assert!(matches!(
    Rgb555Frame::try_new(&buf, 16, 4, 31),
    Err(LegacyRgbFrameError::InsufficientStride(_))
  ));
}

#[cfg(target_pointer_width = "32")]
#[test]
fn rgb555_frame_try_new_rejects_geometry_overflow() {
  let buf: [u8; 0] = [];
  assert!(matches!(
    Rgb555Frame::try_new(&buf, 1, 0x1_0000, 0x1_0000),
    Err(LegacyRgbFrameError::GeometryOverflow(_))
  ));
}

#[test]
fn rgb555_frame_try_new_rejects_plane_too_short() {
  let buf = vec![0u8; 127];
  assert!(matches!(
    Rgb555Frame::try_new(&buf, 16, 4, 32),
    Err(LegacyRgbFrameError::InsufficientPlane(_))
  ));
}

// ---- Bgr555Frame -----------------------------------------------------------

#[test]
fn bgr555_frame_try_new_accepts_valid_tight() {
  let buf = vec![0u8; 16 * 2 * 4];
  Bgr555Frame::try_new(&buf, 16, 4, 32).expect("valid tight stride");
}

#[test]
fn bgr555_frame_try_new_rejects_zero_dimension() {
  let buf = vec![0u8; 32];
  assert!(matches!(
    Bgr555Frame::try_new(&buf, 0, 0, 0),
    Err(LegacyRgbFrameError::ZeroDimension(_))
  ));
}

#[test]
fn bgr555_frame_try_new_rejects_width_overflow() {
  let buf = vec![0u8; 4];
  let w = u32::MAX / 2 + 1;
  assert!(matches!(
    Bgr555Frame::try_new(&buf, w, 1, w),
    Err(LegacyRgbFrameError::WidthOverflow(_))
  ));
}

#[test]
fn bgr555_frame_try_new_rejects_stride_too_small() {
  let buf = vec![0u8; 16 * 2 * 4];
  assert!(matches!(
    Bgr555Frame::try_new(&buf, 16, 4, 31),
    Err(LegacyRgbFrameError::InsufficientStride(_))
  ));
}

#[cfg(target_pointer_width = "32")]
#[test]
fn bgr555_frame_try_new_rejects_geometry_overflow() {
  let buf: [u8; 0] = [];
  assert!(matches!(
    Bgr555Frame::try_new(&buf, 1, 0x1_0000, 0x1_0000),
    Err(LegacyRgbFrameError::GeometryOverflow(_))
  ));
}

#[test]
fn bgr555_frame_try_new_rejects_plane_too_short() {
  let buf = vec![0u8; 127];
  assert!(matches!(
    Bgr555Frame::try_new(&buf, 16, 4, 32),
    Err(LegacyRgbFrameError::InsufficientPlane(_))
  ));
}

// ---- Rgb444Frame -----------------------------------------------------------

#[test]
fn rgb444_frame_try_new_accepts_valid_tight() {
  let buf = vec![0u8; 16 * 2 * 4];
  Rgb444Frame::try_new(&buf, 16, 4, 32).expect("valid tight stride");
}

#[test]
fn rgb444_frame_try_new_rejects_zero_dimension() {
  let buf = vec![0u8; 32];
  assert!(matches!(
    Rgb444Frame::try_new(&buf, 0, 0, 0),
    Err(LegacyRgbFrameError::ZeroDimension(_))
  ));
}

#[test]
fn rgb444_frame_try_new_rejects_width_overflow() {
  let buf = vec![0u8; 4];
  let w = u32::MAX / 2 + 1;
  assert!(matches!(
    Rgb444Frame::try_new(&buf, w, 1, w),
    Err(LegacyRgbFrameError::WidthOverflow(_))
  ));
}

#[test]
fn rgb444_frame_try_new_rejects_stride_too_small() {
  let buf = vec![0u8; 16 * 2 * 4];
  assert!(matches!(
    Rgb444Frame::try_new(&buf, 16, 4, 31),
    Err(LegacyRgbFrameError::InsufficientStride(_))
  ));
}

#[cfg(target_pointer_width = "32")]
#[test]
fn rgb444_frame_try_new_rejects_geometry_overflow() {
  let buf: [u8; 0] = [];
  assert!(matches!(
    Rgb444Frame::try_new(&buf, 1, 0x1_0000, 0x1_0000),
    Err(LegacyRgbFrameError::GeometryOverflow(_))
  ));
}

#[test]
fn rgb444_frame_try_new_rejects_plane_too_short() {
  let buf = vec![0u8; 127];
  assert!(matches!(
    Rgb444Frame::try_new(&buf, 16, 4, 32),
    Err(LegacyRgbFrameError::InsufficientPlane(_))
  ));
}

// ---- Rgb565Frame::new panic -------------------------------------------------

#[test]
#[should_panic(expected = "invalid Rgb565Frame dimensions or plane length")]
fn rgb565_frame_new_panics_on_invalid() {
  let buf = vec![0u8; 1];
  Rgb565Frame::new(&buf, 16, 4, 32);
}

// ---- Bgr565Frame::new panic -------------------------------------------------

#[test]
#[should_panic(expected = "invalid Bgr565Frame dimensions or plane length")]
fn bgr565_frame_new_panics_on_invalid() {
  let buf = vec![0u8; 1];
  Bgr565Frame::new(&buf, 16, 4, 32);
}

// ---- Rgb555Frame::new panic -------------------------------------------------

#[test]
#[should_panic(expected = "invalid Rgb555Frame dimensions or plane length")]
fn rgb555_frame_new_panics_on_invalid() {
  let buf = vec![0u8; 1];
  Rgb555Frame::new(&buf, 16, 4, 32);
}

// ---- Bgr555Frame::new panic -------------------------------------------------

#[test]
#[should_panic(expected = "invalid Bgr555Frame dimensions or plane length")]
fn bgr555_frame_new_panics_on_invalid() {
  let buf = vec![0u8; 1];
  Bgr555Frame::new(&buf, 16, 4, 32);
}

// ---- Rgb444Frame::new panic -------------------------------------------------

#[test]
#[should_panic(expected = "invalid Rgb444Frame dimensions or plane length")]
fn rgb444_frame_new_panics_on_invalid() {
  let buf = vec![0u8; 1];
  Rgb444Frame::new(&buf, 16, 4, 32);
}

// ---- Bgr444Frame::new panic -------------------------------------------------

#[test]
#[should_panic(expected = "invalid Bgr444Frame dimensions or plane length")]
fn bgr444_frame_new_panics_on_invalid() {
  let buf = vec![0u8; 1];
  Bgr444Frame::new(&buf, 16, 4, 32);
}

// ---- Bgr444Frame -----------------------------------------------------------

#[test]
fn bgr444_frame_try_new_accepts_valid_tight() {
  let buf = vec![0u8; 16 * 2 * 4];
  Bgr444Frame::try_new(&buf, 16, 4, 32).expect("valid tight stride");
}

#[test]
fn bgr444_frame_try_new_rejects_zero_dimension() {
  let buf = vec![0u8; 32];
  assert!(matches!(
    Bgr444Frame::try_new(&buf, 0, 0, 0),
    Err(LegacyRgbFrameError::ZeroDimension(_))
  ));
}

#[test]
fn bgr444_frame_try_new_rejects_width_overflow() {
  let buf = vec![0u8; 4];
  let w = u32::MAX / 2 + 1;
  assert!(matches!(
    Bgr444Frame::try_new(&buf, w, 1, w),
    Err(LegacyRgbFrameError::WidthOverflow(_))
  ));
}

#[test]
fn bgr444_frame_try_new_rejects_stride_too_small() {
  let buf = vec![0u8; 16 * 2 * 4];
  assert!(matches!(
    Bgr444Frame::try_new(&buf, 16, 4, 31),
    Err(LegacyRgbFrameError::InsufficientStride(_))
  ));
}

#[cfg(target_pointer_width = "32")]
#[test]
fn bgr444_frame_try_new_rejects_geometry_overflow() {
  let buf: [u8; 0] = [];
  assert!(matches!(
    Bgr444Frame::try_new(&buf, 1, 0x1_0000, 0x1_0000),
    Err(LegacyRgbFrameError::GeometryOverflow(_))
  ));
}

#[test]
fn bgr444_frame_try_new_rejects_plane_too_short() {
  let buf = vec![0u8; 127];
  assert!(matches!(
    Bgr444Frame::try_new(&buf, 16, 4, 32),
    Err(LegacyRgbFrameError::InsufficientPlane(_))
  ));
}
