// Password utilities for MoonVault

pub fn hash_password(password : String) -> String {
  let salt = generate_salt()
  bcrypt_hash(password, 10, salt)
}

pub fn verify_password(password : String, hash : String) -> Bool {
  if hash.has_prefix("$2b$") || hash.has_prefix("$2a$") {
    return bcrypt_verify(password, hash)
  }
  false
}

pub fn hash_password_scrypt(password : String) -> String {
  let salt = random_hex(16)
  let (n, r, p) = scrypt_params_interactive()
  let hash = scrypt(password, salt, n, r, p, 32)
  "$s0$" + salt + "$" + bytes_to_hex(hash)
}

pub fn verify_password_scrypt(password : String, hash : String) -> Bool {
  if !hash.has_prefix("$s0$") { return false }
  let rest = hash[4:]
  let sep = rest.find("$")
  match sep {
    None => false
    Some(idx) => {
      let salt = rest[0:idx].to_owned()
      let hash_hex = rest[idx + 1:].to_owned()
      let (n, r, p) = scrypt_params_interactive()
      let computed = scrypt(password, salt, n, r, p, 32)
      let computed_hex = bytes_to_hex(computed)
      constant_eq_string(computed_hex, hash_hex)
    }
  }
}

pub fn hash_password_argon2id(password : String) -> String {
  let salt = random_hex(16)
  let (t, m, p) = argon2id_params_moderate()
  let hash = argon2id(password, salt, t, m, p, 32)
  "$argon2id$" + salt + "$" + bytes_to_hex(hash)
}

pub fn verify_password_argon2id(password : String, hash : String) -> Bool {
  if !hash.has_prefix("$argon2id$") { return false }
  let rest = hash[10:]
  let sep = rest.find("$")
  match sep {
    None => false
    Some(idx) => {
      let salt = rest[0:idx].to_owned()
      let hash_hex = rest[idx + 1:].to_owned()
      let (t, m, p) = argon2id_params_moderate()
      let computed = argon2id(password, salt, t, m, p, 32)
      let computed_hex = bytes_to_hex(computed)
      constant_eq_string(computed_hex, hash_hex)
    }
  }
}

pub fn password_needs_rehash(hash : String) -> Bool {
  hash.has_prefix("$2a$")
}

pub fn generate_password(length : Int) -> String {
  if length < 8 { return generate_password(8) }
  let upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  let lower = "abcdefghijklmnopqrstuvwxyz"
  let digits = "0123456789"
  let special = "!@#$%^&*()-_=+[]{}|;:,.<>?"

  let all_chars = upper + lower + digits + special
  let mut result = ""
  let mut i = 0
  while i < length {
    let idx = random_int_range(0, all_chars.length())
    result = result + all_chars[idx:idx + 1].to_owned()
    i = i + 1
  }
  result
}

pub fn password_strength(password : String) -> Int {
  let mut score = 0
  let len = password.length()
  if len < 8 { return 0 }
  if len >= 8 { score = score + 10 }
  if len >= 12 { score = score + 10 }
  if len >= 16 { score = score + 10 }
  if len >= 20 { score = score + 10 }

  let mut has_upper = false
  let mut has_lower = false
  let mut has_digit = false
  let mut has_special = false

  let mut i = 0
  while i < len {
    let ch = password[i]
    if ch >= 'A' && ch <= 'Z' { has_upper = true }
    else if ch >= 'a' && ch <= 'z' { has_lower = true }
    else if ch >= '0' && ch <= '9' { has_digit = true }
    else { has_special = true }
    i = i + 1
  }

  if has_upper { score = score + 15 }
  if has_lower { score = score + 5 }
  if has_digit { score = score + 15 }
  if has_special { score = score + 20 }

  let total = (if has_upper { 1 } else { 0 }) + (if has_lower { 1 } else { 0 }) +
              (if has_digit { 1 } else { 0 }) + (if has_special { 1 } else { 0 })
  if total >= 4 { score = score + 15 }
  else if total >= 3 { score = score + 10 }

  let mut repeats = 0
  i = 1
  while i < len {
    if password[i] == password[i - 1] { repeats = repeats + 1 }
    i = i + 1
  }
  if repeats > 0 { score = score - (repeats * 5) }
  if score < 0 { score = 0 }
  if score > 100 { score = 100 }

  score
}

pub fn password_strength_level(password : String) -> String {
  let s = password_strength(password)
  if s < 30 { "weak" }
  else if s < 60 { "fair" }
  else if s < 80 { "strong" }
  else { "very_strong" }
}