///|
fn moongate_client_normalize_base_url(base_url : String) -> String {
  let trimmed = trim_end_slashes(base_url.trim().to_owned())
  if trimmed.is_empty() {
    MOONGATE_DEFAULT_CLIENT_BASE_URL
  } else {
    trimmed
  }
}

///|
fn moongate_client_url(base_url : String, path : String) -> String {
  let normalized = moongate_client_normalize_base_url(base_url)
  let path = if path.has_prefix("/") { path } else { "/\{path}" }
  "\{normalized}\{path}"
}

///|
fn moongate_client_url_with_query(
  base_url : String,
  path : String,
  query : MoonGateUsageQuery?,
) -> String {
  moongate_client_url(base_url, moongate_client_path_with_query(path, query))
}

///|
fn moongate_client_url_with_session_sync_query(
  base_url : String,
  path : String,
  query : MoonGateSessionSyncQuery?,
) -> String {
  moongate_client_url(
    base_url,
    moongate_client_session_sync_path_with_query(path, query),
  )
}

///|
fn moongate_client_path_with_query(
  path : String,
  query : MoonGateUsageQuery?,
) -> String {
  match moongate_usage_query_string(query) {
    Some(query_string) => "\{path}?\{query_string}"
    None => path
  }
}

///|
fn moongate_client_session_sync_path_with_query(
  path : String,
  query : MoonGateSessionSyncQuery?,
) -> String {
  match moongate_session_sync_query_string(query) {
    Some(query_string) => "\{path}?\{query_string}"
    None => path
  }
}

///|
fn moongate_client_proxy_provider_path(
  path : String,
  app_type : String,
  provider_id : String,
) -> String {
  moongate_client_path_with_pairs(path, [
    ("providerId", provider_id),
    ("appType", app_type),
  ])
}

///|
fn moongate_client_path_with_pairs(
  path : String,
  pairs : Array[(String, String)],
) -> String {
  let parts : Array[String] = []
  for pair in pairs {
    let (key, value) = pair
    if !value.trim().is_empty() {
      parts.push(moongate_client_query_pair(key, value))
    }
  }
  if parts.is_empty() {
    path
  } else {
    "\{path}?\{parts.join("&")}"
  }
}

///|
fn moongate_client_path_with_optional_pairs(
  path : String,
  pairs : Array[(String, String?)],
) -> String {
  let parts : Array[String] = []
  for pair in pairs {
    let (key, value) = pair
    match value {
      Some(value) if !value.trim().is_empty() =>
        parts.push(moongate_client_query_pair(key, value))
      _ => ()
    }
  }
  if parts.is_empty() {
    path
  } else {
    "\{path}?\{parts.join("&")}"
  }
}

///|
fn moongate_usage_query_string(query : MoonGateUsageQuery?) -> String? {
  guard query is Some(query) else { return None }
  let parts : Array[String] = []
  match query.start_date {
    Some(value) if !value.trim().is_empty() =>
      parts.push(moongate_client_query_pair("startDate", value))
    _ => ()
  }
  match query.end_date {
    Some(value) if !value.trim().is_empty() =>
      parts.push(moongate_client_query_pair("endDate", value))
    _ => ()
  }
  match query.app_type {
    Some(value) if !value.trim().is_empty() =>
      parts.push(moongate_client_query_pair("appType", value))
    _ => ()
  }
  match query.provider_id {
    Some(value) if !value.trim().is_empty() =>
      parts.push(moongate_client_query_pair("providerId", value))
    _ => ()
  }
  match query.provider_name {
    Some(value) if !value.trim().is_empty() =>
      parts.push(moongate_client_query_pair("providerName", value))
    _ => ()
  }
  match query.model {
    Some(value) if !value.trim().is_empty() =>
      parts.push(moongate_client_query_pair("model", value))
    _ => ()
  }
  match query.status_code {
    Some(value) if !value.trim().is_empty() =>
      parts.push(moongate_client_query_pair("statusCode", value))
    _ => ()
  }
  match query.page {
    Some(value) => parts.push(moongate_client_query_pair("page", "\{value}"))
    None => ()
  }
  match query.page_size {
    Some(value) =>
      parts.push(moongate_client_query_pair("pageSize", "\{value}"))
    None => ()
  }
  if parts.is_empty() {
    None
  } else {
    Some(parts.join("&"))
  }
}

///|
fn moongate_session_sync_query_string(
  query : MoonGateSessionSyncQuery?,
) -> String? {
  guard query is Some(query) else { return None }
  let parts : Array[String] = []
  match query.projects_dir {
    Some(value) if !value.trim().is_empty() =>
      parts.push(moongate_client_query_pair("projectsDir", value))
    _ => ()
  }
  match query.codex_dir {
    Some(value) if !value.trim().is_empty() =>
      parts.push(moongate_client_query_pair("codexDir", value))
    _ => ()
  }
  match query.gemini_dir {
    Some(value) if !value.trim().is_empty() =>
      parts.push(moongate_client_query_pair("geminiDir", value))
    _ => ()
  }
  match query.opencode_export_path {
    Some(value) if !value.trim().is_empty() =>
      parts.push(moongate_client_query_pair("opencodeExportPath", value))
    _ => ()
  }
  match query.opencode_db_path {
    Some(value) if !value.trim().is_empty() =>
      parts.push(moongate_client_query_pair("opencodeDbPath", value))
    _ => ()
  }
  if parts.is_empty() {
    None
  } else {
    Some(parts.join("&"))
  }
}

///|
fn moongate_client_query_pair(key : String, value : String) -> String {
  "\{copilot_url_encode(key)}=\{copilot_url_encode(value)}"
}