import { describe, it, expect } from "vitest";
import { detectTrigger } from "./detectTrigger";

describe("detectTrigger", () => {
  it("detects @query at cursor position", () => {
    expect(detectTrigger("hello @wea", "@", 10)).toEqual({
      query: "wea",
      offset: 6,
    });
  });

  it("returns null when cursor is before the trigger", () => {
    expect(detectTrigger("hello @weather", "@", 5)).toBeNull();
  });

  it("returns null when no trigger character", () => {
    expect(detectTrigger("hello world", "@", 11)).toBeNull();
  });

  it("requires whitespace or start before trigger", () => {
    expect(detectTrigger("email@test", "@", 10)).toBeNull();
  });

  it("trigger at start of text", () => {
    expect(detectTrigger("@foo", "@", 4)).toEqual({
      query: "foo",
      offset: 0,
    });
  });

  it("stops at whitespace in query", () => {
    // "@foo bar" — space terminates the mention
    expect(detectTrigger("@foo bar", "@", 8)).toBeNull();
  });

  it("stops at newline", () => {
    expect(detectTrigger("@foo\nbar", "@", 8)).toBeNull();
  });

  it("stops at tab", () => {
    expect(detectTrigger("@foo\tbar", "@", 8)).toBeNull();
  });

  it("treats tab before trigger as valid boundary", () => {
    expect(detectTrigger("hello\t@foo", "@", 10)).toEqual({
      query: "foo",
      offset: 6,
    });
  });

  it("finds trigger closest to cursor, not earlier ones", () => {
    // Text has two @: "hello @old text @new"
    // Cursor at end → should find @new
    expect(detectTrigger("hello @old text @new", "@", 20)).toEqual({
      query: "new",
      offset: 16,
    });
  });

  it("ignores trigger after cursor", () => {
    // Cursor at position 5, trigger at position 10
    expect(detectTrigger("hello text @foo", "@", 5)).toBeNull();
  });

  it("works with multi-char trigger", () => {
    expect(detectTrigger("hello @@foo", "@@", 11)).toEqual({
      query: "foo",
      offset: 6,
    });
  });

  it("empty query when cursor is right after trigger", () => {
    expect(detectTrigger("hello @", "@", 7)).toEqual({
      query: "",
      offset: 6,
    });
  });

  it("treats U+3000 full-width space before trigger as boundary", () => {
    expect(detectTrigger("全角\u3000@foo", "@", 7)).toEqual({
      query: "foo",
      offset: 3,
    });
  });

  it("treats U+00A0 NBSP before trigger as boundary", () => {
    expect(detectTrigger("x\u00A0@foo", "@", 6)).toEqual({
      query: "foo",
      offset: 2,
    });
  });

  it("stops at U+3000 full-width space inside query", () => {
    expect(detectTrigger("@foo\u3000bar", "@", 8)).toBeNull();
  });

  it("IME full-width space before trigger char acts as boundary", () => {
    expect(detectTrigger("hello\u3000@foo", "@", 10)).toEqual({
      query: "foo",
      offset: 6,
    });
  });

  it("NBSP between word and trigger acts as boundary", () => {
    expect(detectTrigger("hello\u00a0@foo", "@", 10)).toEqual({
      query: "foo",
      offset: 6,
    });
  });

  it("full-width trigger char does NOT match ASCII trigger (literal comparison)", () => {
    expect(detectTrigger("hello \uff20foo", "@", 10)).toBeNull();
  });
});
