/**
 * Calculates the Jaro distance between two strings.
 * The Jaro distance is a measure of similarity between two strings,
 * based on the number of matching characters and transpositions.
 *
 * @param s1 - The first string to compare.
 * @param s2 - The second string to compare.
 * @returns The Jaro distance between the two strings, as a number between 0 and 1.
 */
export function jaroDistance(s1: string, s2: string): number {
  const matchWindow = Math.floor(Math.max(s1.length, s2.length) / 2) - 1

  // Initialize arrays to hold matches and transpositions
  const s1Matches = new Array(s1.length).fill(false)
  const s2Matches = new Array(s2.length).fill(false)
  let transpositions = 0

  // Count matching characters
  let matches = 0
  for (let i = 0; i < s1.length; i++) {
    const start = Math.max(0, i - matchWindow)
    const end = Math.min(i + matchWindow + 1, s2.length)
    for (let j = start; j < end; j++) {
      if (!s2Matches[j] && s1[i] === s2[j]) {
        s1Matches[i] = true
        s2Matches[j] = true
        matches++
        break
      }
    }
  }

  // No matches found
  if (matches === 0) {
    return 0
  }

  // Count transpositions
  let k = 0
  for (let i = 0; i < s1.length; i++) {
    if (s1Matches[i]) {
      while (!s2Matches[k]) {
        k++
      }
      if (s1[i] !== s2[k]) {
        transpositions++
      }
      k++
    }
  }

  transpositions /= 2

  return (
    (matches / s1.length + matches / s2.length + (matches - transpositions) / matches) / 3
  )
}
