///|
// ============================================================================
// TypedQueryResult Conversion
// ============================================================================

///|
/// Convert a QueryResult to a TypedQueryResult by parsing string values.
pub fn QueryResult::to_typed(self : QueryResult) -> TypedQueryResult {
  let column_count = self.column_count()
  let row_count = self.row_count()
  let column_types = self.column_types

  // Initialize column arrays
  let data : Array[Array[Value]] = []
  for col in 0.. Int {
  if self.data.length() == 0 {
    0
  } else {
    self.data[0].length()
  }
}

///|
/// Get the number of columns in the result.
pub fn TypedQueryResult::column_count(self : TypedQueryResult) -> Int {
  self.columns.length()
}

///|
/// Get a value at the specified row and column.
pub fn TypedQueryResult::get_value(
  self : TypedQueryResult,
  row : Int,
  col : Int,
) -> Value? {
  if row < 0 || row >= self.row_count() || col < 0 || col >= self.column_count() {
    None
  } else {
    Some(self.data[col][row])
  }
}

///|
/// Get an Int value at the specified position.
pub fn TypedQueryResult::get_int(
  self : TypedQueryResult,
  row : Int,
  col : Int,
) -> Int? {
  match self.get_value(row, col) {
    Some(Value::Int(i)) => Some(i)
    _ => None
  }
}

///|
/// Get a Double value at the specified position.
pub fn TypedQueryResult::get_double(
  self : TypedQueryResult,
  row : Int,
  col : Int,
) -> Double? {
  match self.get_value(row, col) {
    Some(Value::Double(d)) => Some(d)
    _ => None
  }
}

///|
/// Get a Bool value at the specified position.
pub fn TypedQueryResult::get_bool(
  self : TypedQueryResult,
  row : Int,
  col : Int,
) -> Bool? {
  match self.get_value(row, col) {
    Some(Value::Bool(b)) => Some(b)
    _ => None
  }
}

///|
/// Get a String value at the specified position.
pub fn TypedQueryResult::get_string(
  self : TypedQueryResult,
  row : Int,
  col : Int,
) -> String? {
  match self.get_value(row, col) {
    Some(Value::String(s)) => Some(s)
    _ => None
  }
}

///|
/// Get a Date value (days since epoch) at the specified position.
pub fn TypedQueryResult::get_date(
  self : TypedQueryResult,
  row : Int,
  col : Int,
) -> Int? {
  match self.get_value(row, col) {
    Some(Value::Date(d)) => Some(d)
    _ => None
  }
}

///|
/// Get a Timestamp value (microseconds since epoch) at the specified position.
pub fn TypedQueryResult::get_timestamp(
  self : TypedQueryResult,
  row : Int,
  col : Int,
) -> Int64? {
  match self.get_value(row, col) {
    Some(Value::Timestamp(t)) => Some(t)
    _ => None
  }
}

///|
/// Get a Decimal value at the specified position.
pub fn TypedQueryResult::get_decimal(
  self : TypedQueryResult,
  row : Int,
  col : Int,
) -> Decimal? {
  match self.get_value(row, col) {
    Some(Value::Decimal(d)) => Some(d)
    _ => None
  }
}

///|
/// Get a Blob value at the specified position.
pub fn TypedQueryResult::get_blob(
  self : TypedQueryResult,
  row : Int,
  col : Int,
) -> Bytes? {
  match self.get_value(row, col) {
    Some(Value::Blob(b)) => Some(b)
    _ => None
  }
}

///|
/// Check if the value at the specified position is NULL.
pub fn TypedQueryResult::is_null(
  self : TypedQueryResult,
  row : Int,
  col : Int,
) -> Bool {
  match self.get_value(row, col) {
    Some(Value::Null) => true
    _ => false
  }
}

// ============================================================================
// TypedQueryResult Columnar Access
// ============================================================================

///|
/// Get an entire column as typed values.
pub fn TypedQueryResult::get_column(
  self : TypedQueryResult,
  col : Int,
) -> Array[Value]? {
  if col < 0 || col >= self.column_count() {
    None
  } else {
    Some(self.data[col])
  }
}

///|
/// Get an entire column as Option[Int] values.
pub fn TypedQueryResult::get_int_column(
  self : TypedQueryResult,
  col : Int,
) -> Array[Int?]? {
  match self.get_column(col) {
    Some(column) => {
      let result : Array[Int?] = []
      for value in column {
        match value {
          Value::Int(v) => result.push(Some(v))
          Value::Null => result.push(None)
          _ => result.push(None)
        }
      } else {
        ()
      }
      Some(result)
    }
    None => None
  }
}

///|
/// Get an entire column as Option[Double] values.
pub fn TypedQueryResult::get_double_column(
  self : TypedQueryResult,
  col : Int,
) -> Array[Double?]? {
  match self.get_column(col) {
    Some(column) => {
      let result : Array[Double?] = []
      for value in column {
        match value {
          Value::Double(v) => result.push(Some(v))
          Value::Null => result.push(None)
          _ => result.push(None)
        }
      } else {
        ()
      }
      Some(result)
    }
    None => None
  }
}

///|
/// Get an entire column as Option[Bool] values.
pub fn TypedQueryResult::get_bool_column(
  self : TypedQueryResult,
  col : Int,
) -> Array[Bool?]? {
  match self.get_column(col) {
    Some(column) => {
      let result : Array[Bool?] = []
      for value in column {
        match value {
          Value::Bool(v) => result.push(Some(v))
          Value::Null => result.push(None)
          _ => result.push(None)
        }
      } else {
        ()
      }
      Some(result)
    }
    None => None
  }
}

///|
/// Get an entire column as Option[String] values.
pub fn TypedQueryResult::get_string_column(
  self : TypedQueryResult,
  col : Int,
) -> Array[String?]? {
  match self.get_column(col) {
    Some(column) => {
      let result : Array[String?] = []
      for value in column {
        match value {
          Value::String(v) => result.push(Some(v))
          Value::Null => result.push(None)
          _ => result.push(None)
        }
      } else {
        ()
      }
      Some(result)
    }
    None => None
  }
}

///|
/// Get an entire column as Option[Int] date values.
pub fn TypedQueryResult::get_date_column(
  self : TypedQueryResult,
  col : Int,
) -> Array[Int?]? {
  match self.get_column(col) {
    Some(column) => {
      let result : Array[Int?] = []
      for value in column {
        match value {
          Value::Date(v) => result.push(Some(v))
          Value::Null => result.push(None)
          _ => result.push(None)
        }
      } else {
        ()
      }
      Some(result)
    }
    None => None
  }
}

///|
/// Get an entire column as Option[Int64] timestamp values.
pub fn TypedQueryResult::get_timestamp_column(
  self : TypedQueryResult,
  col : Int,
) -> Array[Int64?]? {
  match self.get_column(col) {
    Some(column) => {
      let result : Array[Int64?] = []
      for value in column {
        match value {
          Value::Timestamp(v) => result.push(Some(v))
          Value::Null => result.push(None)
          _ => result.push(None)
        }
      } else {
        ()
      }
      Some(result)
    }
    None => None
  }
}

///|
/// Get an entire column as Option[Decimal] values.
pub fn TypedQueryResult::get_decimal_column(
  self : TypedQueryResult,
  col : Int,
) -> Array[Decimal?]? {
  match self.get_column(col) {
    Some(column) => {
      let result : Array[Decimal?] = []
      for value in column {
        match value {
          Value::Decimal(v) => result.push(Some(v))
          Value::Null => result.push(None)
          _ => result.push(None)
        }
      } else {
        ()
      }
      Some(result)
    }
    None => None
  }
}

// ============================================================================
// Value Helper Methods
// ============================================================================

///|
/// Get the integer value if present, None otherwise.
pub fn Value::as_int(self : Value) -> Int? {
  match self {
    Int(i) => Some(i)
    _ => None
  }
}

///|
/// Get the double value if present, None otherwise.
pub fn Value::as_double(self : Value) -> Double? {
  match self {
    Double(d) => Some(d)
    _ => None
  }
}

///|
/// Get the boolean value if present, None otherwise.
pub fn Value::as_bool(self : Value) -> Bool? {
  match self {
    Bool(b) => Some(b)
    _ => None
  }
}

///|
/// Get the string value if present, None otherwise.
pub fn Value::as_string(self : Value) -> String? {
  match self {
    String(s) => Some(s)
    _ => None
  }
}

///|
/// Get the date value if present, None otherwise.
pub fn Value::as_date(self : Value) -> Int? {
  match self {
    Date(d) => Some(d)
    _ => None
  }
}

///|
/// Get the timestamp value if present, None otherwise.
pub fn Value::as_timestamp(self : Value) -> Int64? {
  match self {
    Timestamp(t) => Some(t)
    _ => None
  }
}

///|
/// Get the decimal value if present, None otherwise.
pub fn Value::as_decimal(self : Value) -> Decimal? {
  match self {
    Decimal(d) => Some(d)
    _ => None
  }
}

///|
/// Get the blob value if present, None otherwise.
pub fn Value::as_blob(self : Value) -> Bytes? {
  match self {
    Blob(b) => Some(b)
    _ => None
  }
}

///|
/// Check if the value is null.
pub fn Value::is_null(self : Value) -> Bool {
  match self {
    Null => true
    _ => false
  }
}

///|
/// Convert a Value to its string representation.
pub fn Value::to_string(self : Value) -> String {
  match self {
    Int(n) => n.to_string()
    Double(d) => d.to_string()
    Bool(b) => if b { "true" } else { "false" }
    String(s) => s
    Date(days) => {
      // Convert days since epoch to YYYY-MM-DD
      let (y, m, d) = days_to_ymd(days)
      "\{y}-\{pad_int_2(m)}-\{pad_int_2(d)}"
    }
    Timestamp(micros) =>
      // Convert microseconds since epoch to timestamp string
      timestamp_to_string(micros)
    Decimal(dec) =>
      // Convert decimal to string representation
      // For 128-bit decimals, if upper is non-zero we indicate large value
      if dec.upper != 0 {
        ""
      } else {
        let divisor = int_pow10(dec.scale).to_int()
        let whole = dec.lower / divisor
        let frac = Int::abs(dec.lower % divisor)
        if dec.scale == 0 {
          whole.to_string()
        } else {
          "\{whole}.\{pad_int(frac.to_string(), dec.scale)}"
        }
      }
    Blob(_) =>
      // Convert bytes to hex string representation (simplified)
      ""
    Null => "NULL"
  }
}

///|
/// Pad an integer with leading zeros to 2 digits.
fn pad_int_2(n : Int) -> String {
  if n < 10 {
    "0\{n}"
  } else {
    n.to_string()
  }
}

///|
/// Pad a string with leading zeros to specified length.
fn pad_int(s : String, len : Int) -> String {
  if s.length() >= len {
    s
  } else {
    let mut result = s
    for _ in result.length().. (Int, Int, Int) {
  // Simplified calculation - accurate for dates after 1970
  let days_per_4_years = 365 * 4 + 1 // Include one leap year
  let mut remaining = days
  let mut year = 1970

  // Add years in 4-year chunks for efficiency
  while remaining >= days_per_4_years {
    remaining = remaining - days_per_4_years
    year = year + 4
  }

  // Add remaining years
  while remaining >= 365 {
    let days_in_year = if is_leap_year(year) { 366 } else { 365 }
    if remaining < days_in_year {
      break
    }
    remaining = remaining - days_in_year
    year = year + 1
  }

  // Add months
  let mut month = 1
  while remaining >= days_in_month(year, month) {
    remaining = remaining - days_in_month(year, month)
    month = month + 1
  }
  let day = remaining + 1
  (year, month, day)
}

///|
/// Convert microseconds since epoch to timestamp string.
fn timestamp_to_string(micros : Int64) -> String {
  let seconds = micros / 1000000L
  let days = seconds / 86400L
  let secs_in_day = seconds % 86400L
  let (year, month, day) = days_to_ymd(days.to_int())
  let hour = (secs_in_day / 3600L).to_int()
  let minute = (secs_in_day % 3600L / 60L).to_int()
  let second = (secs_in_day % 60L).to_int()
  "\{year}-\{pad_int_2(month)}-\{pad_int_2(day)} \{pad_int_2(hour)}:\{pad_int_2(minute)}:\{pad_int_2(second)}"
}

///|
/// Check if a year is a leap year.
pub fn is_leap_year(year : Int) -> Bool {
  (year % 4 == 0 && year % 100 != 0) || year % 400 == 0
}

///|
/// Get the number of days in a month.
pub fn days_in_month(year : Int, month : Int) -> Int {
  if month == 2 {
    if is_leap_year(year) {
      29
    } else {
      28
    }
  } else if month == 4 || month == 6 || month == 9 || month == 11 {
    30
  } else {
    31
  }
}

///|
/// Compute 10^n for decimal scaling.
pub fn int_pow10(n : Int) -> Int64 {
  if n <= 0 {
    1L
  } else if n == 1 {
    10L
  } else if n == 2 {
    100L
  } else if n == 3 {
    1000L
  } else if n == 4 {
    10000L
  } else if n == 5 {
    100000L
  } else if n == 6 {
    1000000L
  } else if n == 7 {
    10000000L
  } else if n == 8 {
    100000000L
  } else if n == 9 {
    1000000000L
  } else if n == 10 {
    10000000000L
  } else if n == 11 {
    100000000000L
  } else if n == 12 {
    1000000000000L
  } else {
    1L
  } // Limit for now
}