/// IP address parsing utilities for IPv4, IPv6, and IPvFuture

///| Simple integer parsing helper
fn parse_int_simple(s : String) -> Int {
  let chars = s.to_array()
  let mut result = 0
  for i = 0; i < chars.length(); i = i + 1 {
    let digit = Char::to_int(chars[i]) - Char::to_int('0')
    result = result * 10 + digit
  }
  result
}

///| Parse a decimal octet (0-255)
/// dec-octet = DIGIT / %x31-39 DIGIT / "1" 2DIGIT / "2" %x30-34 DIGIT / "25" %x30-35
fn parse_dec_octet(s : String) -> Bool {
  let chars = s.to_array()
  let len = chars.length()
  if len == 0 || len > 3 {
    false
  } else {
    let mut all_digits = true
    for i = 0; i < len; i = i + 1 {
      if not(is_digit(chars[i])) {
        all_digits = false
      }
    }
    if not(all_digits) {
      false
    } else {
      // Convert to integer and check range
      let n = parse_int_simple(s)
      n >= 0 && n <= 255
    }
  }
}

///| Parse IPv4 address: dec-octet "." dec-octet "." dec-octet "." dec-octet
pub fn parse_ipv4_address(s : String) -> URIResult[String] {
  let parts = s.split(".")
  let parts_arr = parts.collect()
  if parts_arr.length() != 4 {
    Err(InvalidHost("IPv4 address must have exactly 4 octets"))
  } else {
    let mut valid = true
    for i = 0; i < 4; i = i + 1 {
      if not(parse_dec_octet(parts_arr[i].to_string())) {
        valid = false
      }
    }
    if valid {
      Ok(s)
    } else {
      Err(InvalidHost("Invalid IPv4 octet values"))
    }
  }
}

///| Parse a 16-bit hex value (h16): 1*4HEXDIG
fn parse_h16(s : String) -> Bool {
  let chars = s.to_array()
  let len = chars.length()
  if len >= 1 && len <= 4 {
    let mut all_hex = true
    for i = 0; i < len; i = i + 1 {
      if not(is_hexdig(chars[i])) {
        all_hex = false
      }
    }
    all_hex
  } else {
    false
  }
}

///| Simplified IPv6 address validation
/// This is a simplified version that checks basic structure
/// A full implementation would need to handle all IPv6 compression rules
pub fn parse_ipv6_address(s : String) -> URIResult[String] {
  let chars = s.to_array()
  let mut colon_count = 0
  let mut has_double_colon = false

  // Check for invalid patterns like ":::"
  if s.contains(":::") {
    return Err(InvalidHost("Invalid IPv6 address: triple colon not allowed"))
  }

  // Count colons and check for double colons
  for i = 0; i < chars.length(); i = i + 1 {
    if chars[i] == ':' {
      colon_count += 1
      if i > 0 && chars[i - 1] == ':' {
        if not(has_double_colon) {
          has_double_colon = true
        } else {
          // Multiple double colons found
          return Err(
            InvalidHost("IPv6 address can have at most one double colon"),
          )
        }
      }
    }
  }

  // Basic validation - IPv6 should have 2-7 colons  
  if colon_count < 2 || colon_count > 7 {
    Err(InvalidHost("Invalid IPv6 address structure"))
  } else {
    // More detailed validation would be needed for production use
    // For now, we'll accept if it meets basic structural requirements
    let parts = s.split(":")
    let parts_arr = parts.collect()
    let mut valid = true
    for i = 0; i < parts_arr.length(); i = i + 1 {
      let part = parts_arr[i].to_string()
      if part.length() > 0 {
        if i == parts_arr.length() - 1 && part.contains(".") {
          // Last part might be IPv4
          match parse_ipv4_address(part) {
            Ok(_) => continue
            Err(_) => valid = false
          }
        } else if not(parse_h16(part)) {
          valid = false
        }
      }
    }
    if valid {
      Ok(s)
    } else {
      Err(InvalidHost("Invalid IPv6 address format"))
    }
  }
}

///| Parse IPvFuture: "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
pub fn parse_ipv_future(s : String) -> URIResult[String] {
  let chars = s.to_array()
  let len = chars.length()
  if len < 4 || chars[0] != 'v' {
    Err(InvalidHost("IPvFuture must start with 'v'"))
  } else {
    // Find the dot
    let mut dot_pos = -1
    for i = 1; i < len; i = i + 1 {
      if chars[i] == '.' {
        dot_pos = i
        break
      }
    }
    if dot_pos == -1 || dot_pos == 1 {
      Err(InvalidHost("IPvFuture must have version number after 'v'"))
    } else {
      // Check hex digits in version
      let mut valid_version = true
      for i = 1; i < dot_pos; i = i + 1 {
        if not(is_hexdig(chars[i])) {
          valid_version = false
        }
      }
      if not(valid_version) {
        Err(InvalidHost("IPvFuture version must be hex digits"))
      } else if dot_pos == len - 1 {
        Err(InvalidHost("IPvFuture must have content after dot"))
      } else {
        // Check remaining characters
        let mut valid_content = true
        for i = dot_pos + 1; i < len; i = i + 1 {
          let c = chars[i]
          if not(is_unreserved(c) || is_sub_delim(c) || c == ':') {
            valid_content = false
          }
        }
        if valid_content {
          Ok(s)
        } else {
          Err(InvalidHost("Invalid characters in IPvFuture"))
        }
      }
    }
  }
}

///| Parse IP literal: "[" ( IPv6address / IPvFuture  ) "]"
pub fn parse_ip_literal(s : String) -> URIResult[HostType] {
  let len = s.length()
  if len < 3 ||
    s.charcode_at(0) != '['.to_int() ||
    s.charcode_at(len - 1) != ']'.to_int() {
    Err(InvalidHost("IP literal must be enclosed in brackets"))
  } else {
    let inner = s.substring(start=1, end=len - 1)
    if inner.has_prefix("v") {
      // IPvFuture
      match parse_ipv_future(inner) {
        Ok(addr) => Ok(IPvFuture(addr))
        Err(e) => Err(e)
      }
    } else {
      // IPv6
      match parse_ipv6_address(inner) {
        Ok(addr) => Ok(IPv6(addr))
        Err(e) => Err(e)
      }
    }
  }
}

///| Parse any host type: IP-literal / IPv4address / reg-name
pub fn parse_host(s : String) -> URIResult[HostType] {
  if s.is_empty() {
    Err(InvalidHost("Host cannot be empty"))
  } else if s.has_prefix("[") {
    // IP literal
    parse_ip_literal(s)
  } else if s.contains(":") {
    // Could be IPv6 without brackets (not standard) or reg-name with colon
    // We'll treat it as reg-name since proper IPv6 should be in brackets
    if is_valid_encoded_string(s, is_reg_name_char) {
      Ok(HostType::RegName(s))
    } else {
      Err(InvalidHost("Invalid characters in host name"))
    }
  } else {
    // Try IPv4 first, then reg-name
    match parse_ipv4_address(s) {
      Ok(addr) => Ok(IPv4(addr))
      Err(_) =>
        if is_valid_encoded_string(s, is_reg_name_char) {
          Ok(HostType::RegName(s))
        } else {
          Err(InvalidHost("Invalid characters in host name"))
        }
    }
  }
}