///|
/// Header and stream-level format helpers for integrations.
pub(all) enum GifVersion {
  Gif87a
  Gif89a
} derive(Eq, Debug)

///|
pub(all) struct GifHeader {
  version : GifVersion
  width : Int
  height : Int
  global_palette : Bool
  color_resolution : Int
  sorted_palette : Bool
  background_index : Int
  aspect_ratio : Int
} derive(Debug)

///|
pub fn GifHeader::version(self : GifHeader) -> GifVersion {
  self.version
}

///|
pub fn GifHeader::width(self : GifHeader) -> Int {
  self.width
}

///|
pub fn GifHeader::height(self : GifHeader) -> Int {
  self.height
}

///|
pub fn GifHeader::global_palette(self : GifHeader) -> Bool {
  self.global_palette
}

///|
pub fn GifHeader::color_resolution(self : GifHeader) -> Int {
  self.color_resolution
}

///|
pub fn GifHeader::sorted_palette(self : GifHeader) -> Bool {
  self.sorted_palette
}

///|
pub fn GifHeader::background_index(self : GifHeader) -> Int {
  self.background_index
}

///|
pub fn GifHeader::aspect_ratio(self : GifHeader) -> Int {
  self.aspect_ratio
}

///|
/// Read the six-byte signature and logical screen descriptor.
pub fn parse_header(data : Bytes) -> GifHeader raise GifError {
  if data.length() < 13 {
    raise UnexpectedEnd(context="GIF format header")
  }
  let version = if data[3] == b'8' && data[4] == b'7' && data[5] == b'a' {
    Gif87a
  } else if data[3] == b'8' && data[4] == b'9' && data[5] == b'a' {
    Gif89a
  } else {
    raise InvalidSignature
  }
  if data[0] != b'G' || data[1] != b'I' || data[2] != b'F' {
    raise InvalidSignature
  }
  let packed = data[10].to_int()
  GifHeader::{
    version,
    width: data[6].to_int() | (data[7].to_int() << 8),
    height: data[8].to_int() | (data[9].to_int() << 8),
    global_palette: (packed & 0x80) != 0,
    color_resolution: ((packed >> 4) & 7) + 1,
    sorted_palette: (packed & 8) != 0,
    background_index: data[11].to_int(),
    aspect_ratio: data[12].to_int(),
  }
}

///|
/// Return a user-facing version string.
pub fn GifVersion::name(self : GifVersion) -> String {
  match self {
    Gif87a => "GIF87a"
    Gif89a => "GIF89a"
  }
}

///|
/// Check only the signature, without requiring complete frame data.
pub fn has_gif_signature(data : Bytes) -> Bool {
  data.length() >= 6 &&
  data[0] == b'G' &&
  data[1] == b'I' &&
  data[2] == b'F' &&
  data[3] == b'8' &&
  (data[4] == b'7' || data[4] == b'9') &&
  data[5] == b'a'
}

///|
/// Return the logical screen area, clamped to a safe integer range.
pub fn GifHeader::area(self : GifHeader) -> Int {
  self.width * self.height
}