// @-tagging (ADR-063) -- ren logikk, ingen React her, så den kan
// enhetstestes uavhengig av komponentene som bruker den (se
// mentions.test.ts). UI-delen (dropdown, tekstfelt, rendering av taggede
// utsnitt) ligger i components/mention-input.tsx.

export type Tag = {
  user_id: string
  display_name: string
  start_index: number
  end_index: number
}

export type TaggablePerson = {
  user_id: string
  display_name: string
}

/** Henter kandidater fra det nye søkeendepunktet (kun faktiske relasjoner
 * -- rundedeltakere + avsenderens venner, ALDRI fritekstsøk i hele
 * brukerbasen, se ADR-063). */
export async function fetchTaggablePeople(roundId: string, query: string): Promise<TaggablePerson[]> {
  const res = await fetch(`/rounds/${roundId}/taggable-people?q=${encodeURIComponent(query)}`, {
    credentials: "include",
  })
  if (!res.ok) return []
  return (await res.json()) as TaggablePerson[]
}

/** Er markøren midt i et "@søketekst"-forsøk? Søker bakover fra markøren
 * gjennom sammenhengende ikke-mellomrom-tegn etter en "@" som enten står
 * helt i starten av teksten eller rett etter et mellomrom (så en e-post-
 * adresse skrevet inn et sted i teksten ikke feilaktig trigger et
 * forslag). Returnerer `null` når det ikke finnes noe aktivt @-forsøk. */
export function detectActiveMention(
  body: string,
  cursor: number,
): { start: number; query: string } | null {
  let i = cursor - 1
  while (i >= 0 && !/\s/.test(body[i])) {
    if (body[i] === "@") {
      const precedingChar = i > 0 ? body[i - 1] : undefined
      if (precedingChar === undefined || /\s/.test(precedingChar)) {
        return { start: i, query: body.slice(i + 1, cursor) }
      }
      return null
    }
    i--
  }
  return null
}

/** Setter inn `@Fornavn Etternavn` der `@søketekst` sto (fra `start` til
 * `cursor`), og returnerer den nye teksten + den ferdige taggen + hvor
 * markøren skal stå etterpå (rett etter navnet). */
export function insertMention(
  body: string,
  start: number,
  cursor: number,
  person: TaggablePerson,
): { body: string; tag: Tag; cursor: number } {
  const inserted = `@${person.display_name}`
  const newBody = body.slice(0, start) + inserted + body.slice(cursor)
  return {
    body: newBody,
    tag: { user_id: person.user_id, display_name: person.display_name, start_index: start, end_index: start + inserted.length },
    cursor: start + inserted.length,
  }
}

/** Justerer eksisterende tags etter en tekstredigering -- differ
 * oldBody/newBody via felles prefiks/suffiks (samme prinsipp som en enkel
 * tekst-diff) i stedet for å anta HVOR endringen skjedde. Tags som ligger
 * HELT før eller HELT etter det redigerte området beholdes (sistnevnte
 * med forskjøvet offset); en tag hvis eget tegn-utsnitt ble RØRT av
 * redigeringen droppes stille -- samme "ikke prøv å reparere en tag som
 * ikke lenger stemmer"-filosofi som backend-valideringen allerede har
 * (se ADR-063 Beslutning C). */
export function adjustTagsForEdit(oldBody: string, newBody: string, tags: Tag[]): Tag[] {
  const maxCommon = Math.min(oldBody.length, newBody.length)
  let prefix = 0
  while (prefix < maxCommon && oldBody[prefix] === newBody[prefix]) prefix++

  let suffix = 0
  const maxSuffix = maxCommon - prefix
  while (
    suffix < maxSuffix &&
    oldBody[oldBody.length - 1 - suffix] === newBody[newBody.length - 1 - suffix]
  ) {
    suffix++
  }

  const oldEditEnd = oldBody.length - suffix
  const delta = newBody.length - oldBody.length

  const result: Tag[] = []
  for (const t of tags) {
    if (t.end_index <= prefix) {
      result.push(t)
    } else if (t.start_index >= oldEditEnd) {
      result.push({ ...t, start_index: t.start_index + delta, end_index: t.end_index + delta })
    }
    // else: redigeringen overlapper taggens eget utsnitt -- droppes.
  }
  return result
}

/** Deler en tekst i vanlige og taggede segmenter, sortert og ikke-
 * overlappende (overlappende tags -- skal aldri skje siden de kommer fra
 * enten insertMention eller server-validerte data, men filtreres bort
 * defensivt om det likevel skjer, fremfor å krasje rendringen). Brukt av
 * <TaggedText> (components/mention-input.tsx). */
export type TextSegment = { text: string; tag: Tag | null }

export function segmentTaggedText(body: string, tags: Tag[]): TextSegment[] {
  const sorted = [...tags].sort((a, b) => a.start_index - b.start_index)
  const segments: TextSegment[] = []
  let cursor = 0
  for (const t of sorted) {
    if (t.start_index < cursor || t.end_index > body.length || t.start_index >= t.end_index) continue
    if (t.start_index > cursor) segments.push({ text: body.slice(cursor, t.start_index), tag: null })
    segments.push({ text: body.slice(t.start_index, t.end_index), tag: t })
    cursor = t.end_index
  }
  if (cursor < body.length) segments.push({ text: body.slice(cursor), tag: null })
  return segments
}
