/**
 * 日志过滤正确性测试
 *
 * **Validates: Requirements 9.2**
 *
 * Property 19: 对任意日志行集合和过滤关键词，过滤后的结果应只包含
 * 含有该关键词的日志行，且不遗漏任何匹配行。
 */

import { describe, it, expect } from "vitest";
import { filterLogLines } from "../pages/_archived/LogViewer";

describe("filterLogLines — 日志过滤正确性", () => {
  /* ---- 1. 空关键词返回所有行 ---- */
  it("空关键词返回所有行", () => {
    const lines = ["INFO 启动", "ERROR 失败", "DEBUG 调试"];
    expect(filterLogLines(lines, "")).toEqual(lines);
  });

  /* ---- 2. 空格关键词返回所有行 ---- */
  it("空格关键词返回所有行", () => {
    const lines = ["行1", "行2", "行3"];
    expect(filterLogLines(lines, "   ")).toEqual(lines);
    expect(filterLogLines(lines, "\t")).toEqual(lines);
  });

  /* ---- 3. 匹配的行被保留 ---- */
  it("匹配的行被保留", () => {
    const lines = ["INFO 启动成功", "ERROR 连接失败", "INFO 处理完成"];
    expect(filterLogLines(lines, "INFO")).toEqual([
      "INFO 启动成功",
      "INFO 处理完成",
    ]);
  });

  /* ---- 4. 不匹配的行被过滤掉 ---- */
  it("不匹配的行被过滤掉", () => {
    const lines = ["INFO ok", "ERROR fail", "WARN slow"];
    const result = filterLogLines(lines, "ERROR");
    expect(result).not.toContain("INFO ok");
    expect(result).not.toContain("WARN slow");
  });

  /* ---- 5. 大小写不敏感匹配 ---- */
  it("大小写不敏感匹配", () => {
    const lines = ["Error occurred", "error found", "ERROR critical"];
    const result = filterLogLines(lines, "error");
    expect(result).toHaveLength(3);
    expect(result).toEqual(lines);
  });

  /* ---- 6. 空行数组返回空数组 ---- */
  it("空行数组返回空数组", () => {
    expect(filterLogLines([], "anything")).toEqual([]);
  });

  /* ---- 7. 所有行都匹配时返回全部 ---- */
  it("所有行都匹配时返回全部", () => {
    const lines = ["log: a", "log: b", "log: c"];
    expect(filterLogLines(lines, "log")).toEqual(lines);
  });

  /* ---- 8. 没有行匹配时返回空数组 ---- */
  it("没有行匹配时返回空数组", () => {
    const lines = ["hello", "world", "foo"];
    expect(filterLogLines(lines, "zzz")).toEqual([]);
  });

  /* ---- 9. 关键词在行首/行中/行尾都能匹配 ---- */
  describe("关键词位置匹配", () => {
    const keyword = "target";

    it("行首匹配", () => {
      expect(filterLogLines(["target is here"], keyword)).toHaveLength(1);
    });

    it("行中匹配", () => {
      expect(filterLogLines(["the target found"], keyword)).toHaveLength(1);
    });

    it("行尾匹配", () => {
      expect(filterLogLines(["found the target"], keyword)).toHaveLength(1);
    });
  });

  /* ---- 10. 特殊字符关键词正常工作 ---- */
  it("特殊字符关键词正常工作", () => {
    const lines = [
      "path: /api/v1/users",
      "regex: [a-z]+",
      "price: $100.00",
      "normal line",
    ];
    // 包含 '/' 的关键词
    expect(filterLogLines(lines, "/api")).toEqual(["path: /api/v1/users"]);
    // 包含 '[' 的关键词
    expect(filterLogLines(lines, "[a-z]")).toEqual(["regex: [a-z]+"]);
    // 包含 '$' 的关键词
    expect(filterLogLines(lines, "$100")).toEqual(["price: $100.00"]);
  });

  /* ---- 11. Property: 过滤结果是原始数组的子集 ---- */
  it("过滤结果是原始数组的子集", () => {
    const lines = ["alpha", "beta", "gamma", "delta", "epsilon"];
    const keywords = ["a", "eta", "xyz", ""];

    for (const kw of keywords) {
      const result = filterLogLines(lines, kw);
      // 结果中的每一行都必须存在于原始数组中
      for (const line of result) {
        expect(lines).toContain(line);
      }
      // 结果长度不超过原始数组
      expect(result.length).toBeLessThanOrEqual(lines.length);
    }
  });

  /* ---- 12. Property: 过滤结果中每一行都包含关键词 ---- */
  it("过滤结果中每一行都包含关键词", () => {
    const lines = [
      "2024-01-01 INFO 启动",
      "2024-01-01 ERROR 数据库连接失败",
      "2024-01-01 WARN 内存不足",
      "2024-01-01 INFO 处理完成",
      "2024-01-01 DEBUG SQL: SELECT *",
    ];
    const keywords = ["INFO", "error", "SQL", "2024", "不存在的关键词"];

    for (const kw of keywords) {
      const result = filterLogLines(lines, kw);
      const lower = kw.toLowerCase();
      for (const line of result) {
        expect(line.toLowerCase()).toContain(lower);
      }
    }
  });

  /* ---- 13. Property: 原始数组中包含关键词的行都在结果中（不遗漏） ---- */
  it("原始数组中包含关键词的行都在结果中（不遗漏）", () => {
    const lines = [
      "INFO 启动",
      "ERROR 失败",
      "INFO 完成",
      "WARN 超时",
      "INFO 关闭",
    ];
    const keyword = "INFO";
    const result = filterLogLines(lines, keyword);
    const lower = keyword.toLowerCase();

    // 手动找出所有应匹配的行
    const expected = lines.filter((l) => l.toLowerCase().includes(lower));
    expect(result).toEqual(expected);

    // 确认没有遗漏：原始数组中每一行如果包含关键词，就必须在结果中
    for (const line of lines) {
      if (line.toLowerCase().includes(lower)) {
        expect(result).toContain(line);
      }
    }
  });

  /* ---- 补充：保持原始顺序 ---- */
  it("过滤结果保持原始顺序", () => {
    const lines = ["c-match", "a-match", "b-no", "d-match"];
    const result = filterLogLines(lines, "match");
    expect(result).toEqual(["c-match", "a-match", "d-match"]);
  });
});
