// RGB color representation with floating-point components (0.0-1.0)
///|
pub struct RGB {
  r : Double
  g : Double
  b : Double
}

// HSL color representation (Hue: 0-360, Saturation: 0-1, Lightness: 0-1)

///|
pub struct HSL {
  h : Double
  s : Double
  l : Double
}

///|
pub fn HSL::new(h : Double, s : Double, l : Double) -> HSL {
  { h, s, l }
}

// HSV color representation (Hue: 0-360, Saturation: 0-1, Value: 0-1)

///|
pub struct HSV {
  h : Double
  s : Double
  v : Double
}

///|
pub fn HSV::new(h : Double, s : Double, v : Double) -> HSV {
  { h, s, v }
}

// Create RGB from 0-255 integer values

///|
pub fn RGB::from_int(r : Int, g : Int, b : Int) -> RGB {
  {
    r: r.to_double() / 255.0,
    g: g.to_double() / 255.0,
    b: b.to_double() / 255.0,
  }
}

// Create RGB from hex string (e.g., "#FF5733" or "FF5733")

///|
pub fn RGB::from_hex(hex : String) -> RGB {
  let h = if hex.has_prefix("#") { hex[1:].to_owned() } else { hex }
  let r = parse_hex_pair(h[0:2].to_owned())
  let g = parse_hex_pair(h[2:4].to_owned())
  let b = parse_hex_pair(h[4:6].to_owned())
  RGB::from_int(r, g, b)
}

///|
fn parse_hex_pair(s : String) -> Int {
  let c1 = hex_char_to_int(s[0].to_int().unsafe_to_char())
  let c2 = hex_char_to_int(s[1].to_int().unsafe_to_char())
  c1 * 16 + c2
}

///|
fn hex_char_to_int(c : Char) -> Int {
  match c {
    '0' => 0
    '1' => 1
    '2' => 2
    '3' => 3
    '4' => 4
    '5' => 5
    '6' => 6
    '7' => 7
    '8' => 8
    '9' => 9
    'a' | 'A' => 10
    'b' | 'B' => 11
    'c' | 'C' => 12
    'd' | 'D' => 13
    'e' | 'E' => 14
    'f' | 'F' => 15
    _ => 0
  }
}

// Convert RGB to hex string

///|
pub fn RGB::to_hex(self : RGB) -> String {
  let r = (self.r * 255.0).to_int()
  let g = (self.g * 255.0).to_int()
  let b = (self.b * 255.0).to_int()
  "#" + int_to_hex(r) + int_to_hex(g) + int_to_hex(b)
}

///|
fn int_to_hex(n : Int) -> String {
  let h1 = n / 16
  let h2 = n % 16
  String::from_array([hex_digit(h1), hex_digit(h2)])
}

///|
fn hex_digit(n : Int) -> Char {
  match n {
    0 => '0'
    1 => '1'
    2 => '2'
    3 => '3'
    4 => '4'
    5 => '5'
    6 => '6'
    7 => '7'
    8 => '8'
    9 => '9'
    10 => 'A'
    11 => 'B'
    12 => 'C'
    13 => 'D'
    14 => 'E'
    15 => 'F'
    _ => '0'
  }
}

// Convert RGB to HSL

///|
pub fn RGB::to_hsl(self : RGB) -> HSL {
  let r = self.r
  let g = self.g
  let b = self.b
  let max = r.max(g.max(b))
  let min = r.min(g.min(b))
  let delta = max - min

  let l = (max + min) / 2.0

  if delta == 0.0 {
    return { h: 0.0, s: 0.0, l }
  }

  let s = if l < 0.5 { delta / (max + min) } else { delta / (2.0 - max - min) }

  let h = if r == max {
    ((g - b) / delta + (if g < b { 6.0 } else { 0.0 })) * 60.0
  } else if g == max {
    ((b - r) / delta + 2.0) * 60.0
  } else {
    ((r - g) / delta + 4.0) * 60.0
  }

  { h, s, l }
}

// Convert HSL to RGB

///|
pub fn HSL::to_rgb(self : HSL) -> RGB {
  let h = self.h
  let s = self.s
  let l = self.l

  if s == 0.0 {
    return { r: l, g: l, b: l }
  }

  let q = if l < 0.5 { l * (1.0 + s) } else { l + s - l * s }
  let p = 2.0 * l - q

  let r = hue_to_rgb(p, q, h + 120.0)
  let g = hue_to_rgb(p, q, h)
  let b = hue_to_rgb(p, q, h - 120.0)

  { r, g, b }
}

///|
fn hue_to_rgb(p : Double, q : Double, t : Double) -> Double {
  let mut t = t
  if t < 0.0 {
    t = t + 360.0
  }
  if t > 360.0 {
    t = t - 360.0
  }

  if t < 60.0 {
    return p + (q - p) * t / 60.0
  }
  if t < 180.0 {
    return q
  }
  if t < 240.0 {
    return p + (q - p) * (240.0 - t) / 60.0
  }
  p
}

// Convert RGB to HSV

///|
pub fn RGB::to_hsv(self : RGB) -> HSV {
  let r = self.r
  let g = self.g
  let b = self.b
  let max = r.max(g.max(b))
  let min = r.min(g.min(b))
  let delta = max - min

  let v = max
  let s = if max == 0.0 { 0.0 } else { delta / max }

  if delta == 0.0 {
    return { h: 0.0, s: 0.0, v }
  }

  let h = if r == max {
    ((g - b) / delta + (if g < b { 6.0 } else { 0.0 })) * 60.0
  } else if g == max {
    ((b - r) / delta + 2.0) * 60.0
  } else {
    ((r - g) / delta + 4.0) * 60.0
  }

  { h, s, v }
}

// Convert HSV to RGB

///|
pub fn HSV::to_rgb(self : HSV) -> RGB {
  let h = self.h
  let s = self.s
  let v = self.v

  if s == 0.0 {
    return { r: v, g: v, b: v }
  }

  let h_i = (h / 60.0).to_int() % 6
  let f = h / 60.0 - h_i.to_double()
  let p = v * (1.0 - s)
  let q = v * (1.0 - f * s)
  let t = v * (1.0 - (1.0 - f) * s)

  match h_i {
    0 => { r: v, g: t, b: p }
    1 => { r: q, g: v, b: p }
    2 => { r: p, g: v, b: t }
    3 => { r: p, g: q, b: v }
    4 => { r: t, g: p, b: v }
    _ => { r: v, g: p, b: q }
  }
}