function normalizeModelName(name: string): string {
  return name
    .toLowerCase()
    .replace(/claude-(opus|sonnet|haiku)-(\d+)[.-](\d+)/g, "claude-$1-$2.$3")
}

export function fuzzyMatchModel(
  target: string,
  available: Set<string>,
  providers?: string[],
): string | null {
  if (available.size === 0) {
    return null
  }

  const targetNormalized = normalizeModelName(target)

  let candidates = Array.from(available)
  if (providers && providers.length > 0) {
    const providerSet = new Set(providers)
    candidates = candidates.filter((model) => {
      const [provider] = model.split("/")
      return providerSet.has(provider!)
    })
  }

  if (candidates.length === 0) {
    return null
  }

  const matches = candidates.filter((model) =>
    normalizeModelName(model).includes(targetNormalized),
  )

  if (matches.length === 0) {
    return null
  }

  const exactMatch = matches.find((model) => normalizeModelName(model) === targetNormalized)
  if (exactMatch) {
    return exactMatch
  }

  const exactModelIdMatches = matches.filter((model) => {
    const modelId = model.split("/").slice(1).join("/")
    return normalizeModelName(modelId) === targetNormalized
  })
  if (exactModelIdMatches.length > 0) {
    return exactModelIdMatches.reduce((shortest, current) =>
      current.length < shortest.length ? current : shortest,
    )
  }

  return matches.reduce((shortest, current) =>
    current.length < shortest.length ? current : shortest,
  )
}

export function isModelAvailable(
  targetModel: string,
  availableModels: Set<string>,
): boolean {
  return fuzzyMatchModel(targetModel, availableModels) !== null
}
