///|
/// Physical degradation noise and illumination models for fiducial marker robustness testing.
pub(all) enum NoiseType {
  Gaussian(Double)
  SaltAndPepper(Double)
  Poisson
  MotionBlur(Int, Double) // (kernel_size, angle_radians)
  Vignetting(Double) // Falloff power
  LinearGradient(Double, Double) // (dx_slope, dy_slope)
} derive(Debug, Eq)

///|
/// Applies motion blur along a specific directional angle theta (simulating rapid robot/camera movement).
pub fn apply_motion_blur(
  img : Image,
  kernel_size : Int,
  angle_rad : Double,
) -> Image {
  let w = img.width
  let h = img.height
  let res = Image::new(w, h)
  let k = if kernel_size < 3 { 3 } else { kernel_size }
  let half_k = k / 2

  let dx = @math.cos(angle_rad)
  let dy = @math.sin(angle_rad)

  for y in 0..= 0 && px < w && py >= 0 && py < h {
          sum += img.get(px, py).to_double()
          count += 1.0
        }
      }

      let avg = if count > 0.0 {
        (sum / count).round().to_int()
      } else {
        img.get(x, y)
      }
      res.set(x, y, avg)
    }
  }

  res
}

///|
/// Applies radial vignetting light falloff (cos^4 law) from optical center.
pub fn apply_lens_vignetting(img : Image, strength : Double) -> Image {
  let w = img.width
  let h = img.height
  let res = Image::new(w, h)
  let cx = w.to_double() * 0.5
  let cy = h.to_double() * 0.5
  let max_radius = (cx * cx + cy * cy).sqrt()

  for y in 0.. 255 { 255 } else { v })
    }
  }

  res
}

///|
/// Applies non-uniform ambient illumination gradient across the canvas.
pub fn apply_lighting_gradient(
  img : Image,
  slope_x : Double,
  slope_y : Double,
) -> Image {
  let w = img.width
  let h = img.height
  let res = Image::new(w, h)

  for y in 0.. 255 { 255 } else { v }
      res.set(x, y, clamped)
    }
  }

  res
}

///|
/// Synthetically occludes a rectangular sub-region inside a quad (simulating finger / cable occlusion).
pub fn apply_marker_occlusion_box(
  img : Image,
  x0 : Int,
  y0 : Int,
  w : Int,
  h : Int,
  fill_color : Int,
) -> Image {
  let res = img.clone()
  for cy in 0..= 0 && px < res.width && py >= 0 && py < res.height {
        res.set(px, py, fill_color)
      }
    }
  }
  res
}