///| Smart HTTP helpers for receive-pack

///|
pub struct HttpResponse {
  status : Int
  headers : Map[String, String]
  body : Bytes
}

///|
pub fn receive_pack_info_refs_response(
  fs : &@bit.RepoFileSystem,
  root : String,
  auth_header : String?,
  token : String,
  agent? : String = "git/moonbit",
) -> HttpResponse raise @bit.GitError {
  if !check_bearer_token(auth_header, token) {
    return {
      status: 401,
      headers: { "Content-Type": "text/plain", "WWW-Authenticate": "Bearer" },
      body: Bytes::from_array([]),
    }
  }
  let adv = build_receive_pack_advertisement(fs, root, agent~)
  let body = build_smart_advertisement("git-receive-pack", adv)
  {
    status: 200,
    headers: {
      "Content-Type": "application/x-git-receive-pack-advertisement",
      "Cache-Control": "no-cache",
      "Pragma": "no-cache",
    },
    body,
  }
}

///|
pub fn receive_pack_response(
  fs : &@bit.FileSystem,
  rfs : &@bit.RepoFileSystem,
  root : String,
  auth_header : String?,
  token : String,
  body : Bytes,
) -> HttpResponse raise @bit.GitError {
  if !check_bearer_token(auth_header, token) {
    return {
      status: 401,
      headers: { "Content-Type": "text/plain", "WWW-Authenticate": "Bearer" },
      body: Bytes::from_array([]),
    }
  }
  let result = receive_pack(fs, rfs, root, body)
  {
    status: 200,
    headers: {
      "Content-Type": "application/x-git-receive-pack-result",
      "Cache-Control": "no-cache",
      "Pragma": "no-cache",
    },
    body: result,
  }
}

///|
fn build_smart_advertisement(service : String, adv : Bytes) -> Bytes {
  let out : Array[Byte] = []
  let line = @protocol.pktline_encode("# service=\{service}\n")
  for b in line {
    out.push(b)
  }
  for b in @protocol.pktline_flush() {
    out.push(b)
  }
  for b in adv {
    out.push(b)
  }
  Bytes::from_array(FixedArray::makei(out.length(), i => out[i]))
}

///|
fn check_bearer_token(auth_header : String?, token : String) -> Bool {
  match auth_header {
    None => false
    Some(value) => {
      if !value.has_prefix("Bearer ") {
        return false
      }
      let received = String::unsafe_substring(
        value,
        start=7,
        end=value.length(),
      )
      received == token
    }
  }
}