import { describe, it, expect } from "bun:test";
import {
  chunkText,
  stripMentionTags,
  wasBotMentioned,
  normalizeConversationId,
  escapeXml,
  sanitizeFilename,
  accumulateStreamText,
} from "./utils";

describe("chunkText", () => {
  it("returns single chunk for short text", () => {
    expect(chunkText("Hello world")).toEqual(["Hello world"]);
  });

  it("splits at newline boundary", () => {
    const line = "x".repeat(3000);
    const text = `${line}\n${"y".repeat(3000)}`;
    const chunks = chunkText(text);
    expect(chunks.length).toBe(2);
    expect(chunks[0]).toBe(line);
  });

  it("handles text with no good break points", () => {
    const text = "x".repeat(8000);
    const chunks = chunkText(text);
    expect(chunks.length).toBe(2);
    expect(chunks[0].length).toBe(4000);
  });

  it("returns empty array content unchanged", () => {
    expect(chunkText("")).toEqual([""]);
  });
});

describe("stripMentionTags", () => {
  it("strips at tags", () => {
    expect(stripMentionTags('<at id="123">Exult Agent</at> hello')).toBe("hello");
  });

  it("handles text with no mentions", () => {
    expect(stripMentionTags("just text")).toBe("just text");
  });

  it("strips multiple mentions", () => {
    expect(stripMentionTags('<at id="1">Bot</at> and <at id="2">User</at> chat')).toBe("and  chat");
  });
});

describe("wasBotMentioned", () => {
  it("detects mention", () => {
    expect(
      wasBotMentioned({
        recipient: { id: "bot-123" },
        entities: [{ type: "mention", mentioned: { id: "bot-123" } }],
      }),
    ).toBe(true);
  });

  it("returns false when not mentioned", () => {
    expect(
      wasBotMentioned({
        recipient: { id: "bot-123" },
        entities: [{ type: "mention", mentioned: { id: "other" } }],
      }),
    ).toBe(false);
  });

  it("returns false with no entities", () => {
    expect(wasBotMentioned({ recipient: { id: "bot-123" } })).toBe(false);
  });
});

describe("accumulateStreamText", () => {
  it("extends when incoming starts with prior", () => {
    expect(accumulateStreamText("Loading...", "Loading... Done!")).toBe("Loading... Done!");
  });

  it("appends when incoming is unrelated", () => {
    expect(accumulateStreamText("First", "Second")).toBe("FirstSecond");
  });

  it("handles empty prior", () => {
    expect(accumulateStreamText("", "Hello")).toBe("Hello");
  });

  it("handles identical strings", () => {
    expect(accumulateStreamText("Same", "Same")).toBe("Same");
  });
});

describe("normalizeConversationId", () => {
  it("strips messageid suffix", () => {
    expect(normalizeConversationId("a:123;messageid=456")).toBe("a:123");
  });

  it("returns id unchanged when no suffix", () => {
    expect(normalizeConversationId("a:123")).toBe("a:123");
  });
});

describe("escapeXml", () => {
  it("escapes special characters", () => {
    expect(escapeXml('<script>"alert(\'xss\')&"</script>')).toBe(
      "&lt;script&gt;&quot;alert(&apos;xss&apos;)&amp;&quot;&lt;/script&gt;",
    );
  });
});

describe("sanitizeFilename", () => {
  it("removes path traversal characters", () => {
    expect(sanitizeFilename("../../etc/passwd")).toBe(".._.._etc_passwd");
  });

  it("preserves safe characters", () => {
    expect(sanitizeFilename("report-2026.pdf")).toBe("report-2026.pdf");
  });

  it("handles spaces and special chars", () => {
    expect(sanitizeFilename("my file (1).doc")).toBe("my_file__1_.doc");
  });
});

describe("card action handling", () => {
  it("parses Action.Submit data", () => {
    const submitData = { action: "approve", planId: "teams-enhancements" };
    const actionText = `[Card Action] ${JSON.stringify(submitData)}`;
    expect(actionText).toContain('"action":"approve"');
  });

  it("distinguishes card actions in metadata", () => {
    const meta = {
      is_card_action: "true",
      card_action_data: JSON.stringify({ action: "reject" }),
    };
    expect(meta.is_card_action).toBe("true");
    const parsed = JSON.parse(meta.card_action_data);
    expect(parsed.action).toBe("reject");
  });
});
