// Mastodon Pass §9.3.17: shared character counter for the composer.
//
// Mastodon counts every URL as `characters_reserved_per_url` (typically 23)
// regardless of the URL's actual length; this matches the server's
// pre-publish length validation. Pixelfed counts raw characters and does
// not publish a URL reservation, so callers pass `null` to get the raw
// count.
//
// Counts by Unicode code points (`Array.from(text).length`) rather than
// UTF-16 code units so a single emoji or astral character contributes 1,
// matching Mastodon's server-side `Status.text` length validation.

// Local URL regex — intentionally not shared with `AutolinkText.tsx`. The
// composer counter runs on every keystroke and must stay decoupled from the
// rendering primitive's regex set; if the autolinker ever tightens or relaxes
// what it considers a URL (mentions inside a path, etc.) we don't want a
// silent drift in the character count. Keep this pattern broad and stable.
const URL_REGEX =
  /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/g

function codePointLength(s: string): number {
  return Array.from(s).length
}

/**
 * Count the characters of `text` for the purpose of the composer's
 * "X / max" indicator and the post-time length validation.
 *
 * @param charactersReservedPerUrl  Mastodon-style URL reservation. `null`
 *   means raw counting (Pixelfed semantics).
 */
export function countStatusCharacters(
  text: string,
  charactersReservedPerUrl: number | null
): number {
  if (charactersReservedPerUrl === null || charactersReservedPerUrl <= 0) {
    return codePointLength(text)
  }
  let urlPayloadLength = 0
  let urlCount = 0
  for (const match of text.matchAll(URL_REGEX)) {
    urlPayloadLength += codePointLength(match[0])
    urlCount++
  }
  return codePointLength(text) - urlPayloadLength + urlCount * charactersReservedPerUrl
}
