/// Main URI parsing functionality
/// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

///|
/// Parse a complete URI string
pub fn parse_uri(uri_string : String) -> URIResult[URI] {
  if uri_string.is_empty() {
    return Err(MalformedURI("URI cannot be empty"))
  }

  // Find the scheme (everything before first ':')
  let colon_pos = find_char_index(uri_string, ':')
  match colon_pos {
    None => Err(MalformedURI("URI must contain a scheme"))
    Some(pos) =>
      if pos == 0 {
        Err(InvalidScheme("Scheme cannot be empty"))
      } else {
        let scheme_str = uri_string[0:pos].to_owned()
        let remaining = uri_string[pos + 1:].to_owned()
        match parse_scheme(scheme_str) {
          Err(e) => Err(e)
          Ok(scheme) => parse_hier_part_and_rest(scheme, remaining)
        }
      }
  }
}

///|
/// Find first occurrence of character in string
pub fn find_char_index(s : String, c : Char) -> Int? {
  let chars = s.to_array()
  for i = 0; i < chars.length(); i = i + 1 {
    if chars[i] == c {
      return Some(i)
    }
  }
  None
}

///|
/// Parse hier-part and optional query/fragment
/// hier-part = "//" authority path-abempty / path-absolute / path-rootless / path-empty
fn parse_hier_part_and_rest(
  scheme : String,
  remaining : String,
) -> URIResult[URI] {
  // Check for fragment first (everything after '#')
  let (before_fragment, fragment) = split_at_last_char(remaining, '#')

  // Then check for query (everything after '?' but before fragment)
  let (hier_part, query) = split_at_last_char(before_fragment, '?')

  // Parse hier-part
  match parse_hier_part(hier_part) {
    Err(e) => Err(e)
    Ok((authority, path, path_type)) => {
      // Validate query
      let validated_query = match query {
        Some(q) =>
          match parse_query(q) {
            Ok(valid_q) => Some(valid_q)
            Err(e) => return Err(e)
          }
        None => None
      }

      // Validate fragment  
      let validated_fragment = match fragment {
        Some(f) =>
          match parse_fragment(f) {
            Ok(valid_f) => Some(valid_f)
            Err(e) => return Err(e)
          }
        None => None
      }
      Ok({
        scheme,
        authority,
        path,
        path_type,
        query: validated_query,
        fragment: validated_fragment,
      })
    }
  }
}

///|
/// Split string at the last occurrence of a character
fn split_at_last_char(s : String, delimiter : Char) -> (String, String?) {
  match find_last_index_str(s, delimiter.to_string()) {
    Some(pos) => {
      let before = s[0:pos].to_owned()
      let after = s[pos + 1:].to_owned()
      (before, Some(after))
    }
    None => (s, None)
  }
}

///|
/// Parse hier-part component
fn parse_hier_part(
  hier_part : String,
) -> URIResult[(Authority?, String, PathType)] {
  if hier_part.has_prefix("//") {
    // Authority present
    parse_authority_and_path_abempty(hier_part[2:].to_owned())
  } else {
    // No authority, determine path type
    match classify_and_validate_path(hier_part) {
      Ok((path_type, path)) => Ok((None, path, path_type))
      Err(e) => Err(e)
    }
  }
}

///|
/// Parse authority followed by path-abempty
/// Find last occurrence of substring in string (helper function)
pub fn find_last_index_str(s : String, substr : String) -> Int? {
  let s_len = s.length()
  let substr_len = substr.length()
  if substr_len == 0 || substr_len > s_len {
    return None
  }
  for i = s_len - substr_len; i >= 0; i = i - 1 {
    if s[i:i + substr_len] == substr {
      return Some(i)
    }
  }
  None
}

///|
fn parse_authority_and_path_abempty(
  s : String,
) -> URIResult[(Authority?, String, PathType)] {
  // Find where authority ends and path begins
  // Authority ends at the first '/' that starts the path
  let slash_pos = find_authority_end(s)
  let (authority_str, path) = match slash_pos {
    Some(pos) => (s[0:pos].to_owned(), s[pos:].to_owned())
    None => (s, "")
  }
  if authority_str.is_empty() {
    Err(InvalidAuthority("Authority cannot be empty after '//'"))
  } else {
    match parse_authority(authority_str) {
      Err(e) => Err(e)
      Ok(authority) =>
        match validate_path_abempty(path) {
          Err(e) => Err(e)
          Ok(validated_path) => Ok((Some(authority), validated_path, AbEmpty))
        }
    }
  }
}

///|
/// Find where authority component ends (at first '/' that starts path)
/// This is tricky because IPv6 addresses in brackets can contain '/'
fn find_authority_end(s : String) -> Int? {
  let chars = s.to_array()
  let len = chars.length()
  let mut in_brackets = false
  for i = 0; i < len; i = i + 1 {
    match chars[i] {
      '[' => in_brackets = true
      ']' => in_brackets = false
      '/' => if !in_brackets { return Some(i) }
      _ => ()
    }
  }
  None
}

///|
/// Parse a URI reference (URI or relative reference)
/// URI-reference = URI / relative-ref
pub fn parse_uri_reference(uri_ref_string : String) -> URIResult[URI] {
  if uri_ref_string.is_empty() {
    return Err(MalformedURI("URI reference cannot be empty"))
  }

  // Try to parse as URI first (look for scheme)
  let colon_pos = find_scheme_end(uri_ref_string)
  match colon_pos {
    Some(_) =>
      // Has scheme, parse as URI
      parse_uri(uri_ref_string)
    None =>
      // No scheme, parse as relative reference
      parse_relative_reference(uri_ref_string)
  }
}

///|
/// Find the end of a scheme (first ':' that's not part of IPv6 address or port)
fn find_scheme_end(s : String) -> Int? {
  let chars = s.to_array()
  let len = chars.length()

  // Scheme must start with ALPHA
  if len == 0 || !is_alpha(chars[0]) {
    return None
  }

  // Look for first ':' that could end a scheme
  for i = 1; i < len; i = i + 1 {
    let c = chars[i]
    if c == ':' {
      // Check if this looks like a scheme (all previous chars are scheme chars)
      let mut is_scheme = true
      for j = 1; j < i; j = j + 1 {
        if !is_scheme_char(chars[j]) {
          is_scheme = false
          break
        }
      }
      if is_scheme {
        return Some(i)
      }
    } else if !is_scheme_char(c) {
      // Invalid scheme character, so no scheme
      return None
    }
  }
  None
}

///|
/// Parse relative reference
/// relative-ref = relative-part [ "?" query ] [ "#" fragment ]
fn parse_relative_reference(rel_ref : String) -> URIResult[URI] {
  // Use empty scheme for relative references
  let scheme = ""

  // Parse similar to URI but without scheme
  let (before_fragment, fragment) = split_at_last_char(rel_ref, '#')
  let (relative_part, query) = split_at_last_char(before_fragment, '?')

  // Parse relative-part
  match parse_relative_part(relative_part) {
    Err(e) => Err(e)
    Ok((authority, path, path_type)) => {
      // Validate query
      let validated_query = match query {
        Some(q) =>
          match parse_query(q) {
            Ok(valid_q) => Some(valid_q)
            Err(e) => return Err(e)
          }
        None => None
      }

      // Validate fragment
      let validated_fragment = match fragment {
        Some(f) =>
          match parse_fragment(f) {
            Ok(valid_f) => Some(valid_f)
            Err(e) => return Err(e)
          }
        None => None
      }
      Ok({
        scheme,
        authority,
        path,
        path_type,
        query: validated_query,
        fragment: validated_fragment,
      })
    }
  }
}

///|
/// Parse relative-part
/// relative-part = "//" authority path-abempty / path-absolute / path-noscheme / path-empty
fn parse_relative_part(
  relative_part : String,
) -> URIResult[(Authority?, String, PathType)] {
  if relative_part.has_prefix("//") {
    // Authority present
    parse_authority_and_path_abempty(relative_part[2:].to_owned())
  } else {
    // No authority, classify path type
    match classify_and_validate_path(relative_part) {
      Ok((path_type, path)) => Ok((None, path, path_type))
      Err(e) => Err(e)
    }
  }
}