// Color utilities and predefined colors

///|
/// Create a color from RGBA components
pub fn rgba(r : Double, g : Double, b : Double, a : Double) -> Color {
  { r, g, b, a }
}

///|
/// Create a color from RGB components (alpha = 1.0)
pub fn rgb(r : Double, g : Double, b : Double) -> Color {
  { r, g, b, a: 1.0 }
}

///|
/// Create a grayscale color
pub fn gray(value : Double) -> Color {
  { r: value, g: value, b: value, a: 1.0 }
}

///|
/// Transparent color
pub fn transparent() -> Color {
  { r: 0.0, g: 0.0, b: 0.0, a: 0.0 }
}

// Predefined colors

///|
pub fn black() -> Color {
  rgb(0.0, 0.0, 0.0)
}

///|
pub fn white() -> Color {
  rgb(1.0, 1.0, 1.0)
}

///|
pub fn red() -> Color {
  rgb(1.0, 0.0, 0.0)
}

///|
pub fn green() -> Color {
  rgb(0.0, 1.0, 0.0)
}

///|
pub fn blue() -> Color {
  rgb(0.0, 0.0, 1.0)
}

///|
pub fn yellow() -> Color {
  rgb(1.0, 1.0, 0.0)
}

///|
pub fn cyan() -> Color {
  rgb(0.0, 1.0, 1.0)
}

///|
pub fn magenta() -> Color {
  rgb(1.0, 0.0, 1.0)
}

///|
pub fn gold() -> Color {
  rgb(1.0, 0.843, 0.0)
}

///|
pub fn orange() -> Color {
  rgb(1.0, 0.647, 0.0)
}

///|
pub fn purple() -> Color {
  rgb(0.5, 0.0, 0.5)
}

///|
/// Blend two colors using alpha compositing
pub fn blend(c1 : Color, c2 : Color) -> Color {
  let alpha = c1.a + c2.a * (1.0 - c1.a)
  if alpha == 0.0 {
    transparent()
  } else {
    let inv_alpha = 1.0 / alpha
    {
      r: (c1.r * c1.a + c2.r * c2.a * (1.0 - c1.a)) * inv_alpha,
      g: (c1.g * c1.a + c2.g * c2.a * (1.0 - c1.a)) * inv_alpha,
      b: (c1.b * c1.a + c2.b * c2.a * (1.0 - c1.a)) * inv_alpha,
      a: alpha,
    }
  }
}

///|
/// Multiply color by a scalar
pub fn scale(c : Color, factor : Double) -> Color {
  { r: c.r * factor, g: c.g * factor, b: c.b * factor, a: c.a }
}

///|
/// Convert color to hex string
pub fn to_hex(c : Color) -> String {
  let r = (c.r * 255.0).to_int()
  let g = (c.g * 255.0).to_int()
  let b = (c.b * 255.0).to_int()
  fn int_to_hex(n : Int) -> String {
    let hex_chars = [
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
      'F',
    ]
    let high = n / 16
    let low = n % 16
    String::from_array([hex_chars[high], hex_chars[low]])
  }

  "#" + int_to_hex(r) + int_to_hex(g) + int_to_hex(b)
}

///|
/// Clamp color components to valid range [0.0, 1.0]
pub fn clamp(c : Color) -> Color {
  fn clamp_component(x : Double) -> Double {
    if x < 0.0 {
      0.0
    } else if x > 1.0 {
      1.0
    } else {
      x
    }
  }

  {
    r: clamp_component(c.r),
    g: clamp_component(c.g),
    b: clamp_component(c.b),
    a: clamp_component(c.a),
  }
}

///|
/// Create color from HSV (Hue, Saturation, Value)
pub fn hsv(h : Double, s : Double, v : Double) -> Color {
  let h_norm = h - (h / 360.0).floor() * 360.0 // Normalize hue to [0, 360)
  let c = v * s
  let x = c * (1.0 - (h_norm / 60.0 % 2.0 - 1.0).abs())
  let m = v - c
  let (r_prime, g_prime, b_prime) = if h_norm < 60.0 {
    (c, x, 0.0)
  } else if h_norm < 120.0 {
    (x, c, 0.0)
  } else if h_norm < 180.0 {
    (0.0, c, x)
  } else if h_norm < 240.0 {
    (0.0, x, c)
  } else if h_norm < 300.0 {
    (x, 0.0, c)
  } else {
    (c, 0.0, x)
  }
  rgb(r_prime + m, g_prime + m, b_prime + m)
}

///|
/// Interpolate between two colors
pub fn lerp_color(c1 : Color, c2 : Color, t : Double) -> Color {
  let t_clamped = if t < 0.0 { 0.0 } else if t > 1.0 { 1.0 } else { t }
  {
    r: c1.r + (c2.r - c1.r) * t_clamped,
    g: c1.g + (c2.g - c1.g) * t_clamped,
    b: c1.b + (c2.b - c1.b) * t_clamped,
    a: c1.a + (c2.a - c1.a) * t_clamped,
  }
}

///|
/// Multiply blend mode
pub fn multiply_blend(c1 : Color, c2 : Color) -> Color {
  {
    r: c1.r * c2.r,
    g: c1.g * c2.g,
    b: c1.b * c2.b,
    a: c1.a + c2.a - c1.a * c2.a, // Alpha compositing
  }
}

///|
/// Screen blend mode  
pub fn screen_blend(c1 : Color, c2 : Color) -> Color {
  {
    r: 1.0 - (1.0 - c1.r) * (1.0 - c2.r),
    g: 1.0 - (1.0 - c1.g) * (1.0 - c2.g),
    b: 1.0 - (1.0 - c1.b) * (1.0 - c2.b),
    a: c1.a + c2.a - c1.a * c2.a,
  }
}

///|
/// Overlay blend mode
pub fn overlay_blend(c1 : Color, c2 : Color) -> Color {
  fn overlay_component(base : Double, overlay : Double) -> Double {
    if base < 0.5 {
      2.0 * base * overlay
    } else {
      1.0 - 2.0 * (1.0 - base) * (1.0 - overlay)
    }
  }

  {
    r: overlay_component(c1.r, c2.r),
    g: overlay_component(c1.g, c2.g),
    b: overlay_component(c1.b, c2.b),
    a: c1.a + c2.a - c1.a * c2.a,
  }
}

///|
/// Hard light blend mode
pub fn hard_light_blend(c1 : Color, c2 : Color) -> Color {
  overlay_blend(c2, c1) // Hard light is overlay with arguments swapped
}

///|
/// Soft light blend mode
pub fn soft_light_blend(c1 : Color, c2 : Color) -> Color {
  fn soft_light_component(base : Double, overlay : Double) -> Double {
    if overlay < 0.5 {
      base - (1.0 - 2.0 * overlay) * base * (1.0 - base)
    } else {
      let d = if base < 0.25 {
        ((16.0 * base - 12.0) * base + 4.0) * base
      } else {
        base.sqrt()
      }
      base + (2.0 * overlay - 1.0) * (d - base)
    }
  }

  {
    r: soft_light_component(c1.r, c2.r),
    g: soft_light_component(c1.g, c2.g),
    b: soft_light_component(c1.b, c2.b),
    a: c1.a + c2.a - c1.a * c2.a,
  }
}