import { describe, expect, it } from "vitest"
import { adjustTagsForEdit, detectActiveMention, insertMention, segmentTaggedText } from "./mentions"

describe("detectActiveMention", () => {
  it("finner @-forsøk ved starten av teksten", () => {
    expect(detectActiveMention("@Fre", 4)).toEqual({ start: 0, query: "Fre" })
  })

  it("finner @-forsøk midt i teksten, etter mellomrom", () => {
    const body = "God runde med @Fre"
    expect(detectActiveMention(body, body.length)).toEqual({ start: 14, query: "Fre" })
  })

  it("trigges IKKE av en e-post-adresse (@ uten forutgående mellomrom)", () => {
    const body = "kontakt meg på navn@example"
    expect(detectActiveMention(body, body.length)).toBeNull()
  })

  it("returnerer null når markøren ikke er i et @-forsøk i det hele tatt", () => {
    expect(detectActiveMention("bare vanlig tekst", 5)).toBeNull()
  })

  it("returnerer null når @-forsøket ble avbrutt av et mellomrom (fullført/forlatt)", () => {
    const body = "@Fredrik er kul"
    expect(detectActiveMention(body, body.length)).toBeNull()
  })

  it("virker med markøren midt i ordet, ikke bare på slutten", () => {
    const body = "@Fredrik Mathisen"
    // markør rett etter "Fre" i "Fredrik"
    expect(detectActiveMention(body, 4)).toEqual({ start: 0, query: "Fre" })
  })
})

describe("insertMention", () => {
  it("erstatter @søketekst med @Fullt Navn og regner riktig ny markørposisjon", () => {
    const body = "God runde med @Fre i dag"
    const start = 14
    const cursor = 18 // rett etter "Fre"
    const result = insertMention(body, start, cursor, { user_id: "u1", display_name: "Fredrik Mathisen" })
    expect(result.body).toBe("God runde med @Fredrik Mathisen i dag")
    expect(result.tag).toEqual({ user_id: "u1", display_name: "Fredrik Mathisen", start_index: 14, end_index: 31 })
    expect(result.cursor).toBe(31)
    // Taggens eget utsnitt skal faktisk væra "@Fredrik Mathisen".
    expect(result.body.slice(result.tag.start_index, result.tag.end_index)).toBe("@Fredrik Mathisen")
  })
})

describe("adjustTagsForEdit", () => {
  const tag = { user_id: "u1", display_name: "Fredrik Mathisen", start_index: 14, end_index: 32 }

  it("beholder taggen uendret når redigeringen skjer ETTER den", () => {
    const oldBody = "God runde med @Fredrik Mathisen i dag"
    const newBody = "God runde med @Fredrik Mathisen i dag, supert vær"
    const result = adjustTagsForEdit(oldBody, newBody, [tag])
    expect(result).toEqual([tag])
  })

  it("forskyver taggen når tekst settes inn FØR den", () => {
    const oldBody = "med @Fredrik Mathisen i dag"
    const newBody = "God runde med @Fredrik Mathisen i dag"
    const shifted = { ...tag, start_index: 0, end_index: 18 } // relativt til oldBody sin tag
    const oldTag = { ...tag, start_index: 4, end_index: 22 }
    const result = adjustTagsForEdit(oldBody, newBody, [oldTag])
    const delta = newBody.length - oldBody.length
    expect(result).toEqual([{ ...oldTag, start_index: oldTag.start_index + delta, end_index: oldTag.end_index + delta }])
  })

  it("dropper taggen stille når redigeringen overlapper dens eget utsnitt", () => {
    const oldBody = "med @Fredrik Mathisen i dag"
    const oldTag = { ...tag, start_index: 4, end_index: 22 }
    // Sletter en bokstav MIDT i det taggede navnet.
    const newBody = "med @Fredrik athisen i dag"
    const result = adjustTagsForEdit(oldBody, newBody, [oldTag])
    expect(result).toEqual([])
  })

  it("dropper KUN den berørte taggen, beholder en urørt tag et annet sted", () => {
    const oldBody = "@Fredrik og @Kari spilte i dag"
    const fredrikTag = { user_id: "u1", display_name: "Fredrik", start_index: 0, end_index: 8 }
    const kariTag = { user_id: "u2", display_name: "Kari", start_index: 12, end_index: 17 }
    // Redigerer midt i "Fredrik".
    const newBody = "@Fred og @Kari spilte i dag"
    const result = adjustTagsForEdit(oldBody, newBody, [fredrikTag, kariTag])
    const delta = newBody.length - oldBody.length
    expect(result).toEqual([{ ...kariTag, start_index: kariTag.start_index + delta, end_index: kariTag.end_index + delta }])
  })
})

describe("segmentTaggedText", () => {
  it("deler teksten korrekt rundt én tag", () => {
    const body = "God runde med @Fredrik Mathisen i dag"
    const tag = { user_id: "u1", display_name: "Fredrik Mathisen", start_index: 14, end_index: 31 }
    const segments = segmentTaggedText(body, [tag])
    expect(segments).toEqual([
      { text: "God runde med ", tag: null },
      { text: "@Fredrik Mathisen", tag },
      { text: " i dag", tag: null },
    ])
  })

  it("returnerer hele teksten som ett segment når det ikke finnes tags", () => {
    const segments = segmentTaggedText("bare vanlig tekst", [])
    expect(segments).toEqual([{ text: "bare vanlig tekst", tag: null }])
  })

  it("håndterer flere tags i rekkefølge", () => {
    const body = "@Fredrik og @Kari spilte"
    const t1 = { user_id: "u1", display_name: "Fredrik", start_index: 0, end_index: 8 }
    const t2 = { user_id: "u2", display_name: "Kari", start_index: 12, end_index: 17 }
    const segments = segmentTaggedText(body, [t1, t2])
    expect(segments.map((s) => s.text)).toEqual(["@Fredrik", " og ", "@Kari", " spilte"])
  })

  it("hopper defensivt over en tag med ugyldig/utenfor-grense offset i stedet for å krasje", () => {
    const body = "kort tekst"
    const badTag = { user_id: "u1", display_name: "X", start_index: 5, end_index: 999 }
    expect(() => segmentTaggedText(body, [badTag])).not.toThrow()
    expect(segmentTaggedText(body, [badTag])).toEqual([{ text: "kort tekst", tag: null }])
  })
})
