import { describe, it, expect } from "vitest";
import { orchestrate } from "../../src/aggregation/orchestrator.js";

describe("Orchestrator", () => {
  describe("全部成功", () => {
    it("返回所有结果且 partial=false", async () => {
      const result = await orchestrate({
        a: Promise.resolve("value-a"),
        b: Promise.resolve(42),
        c: Promise.resolve({ key: "val" }),
      });

      expect(result.partial).toBe(false);
      expect(result.failures).toHaveLength(0);
      expect(result.results.a).toBe("value-a");
      expect(result.results.b).toBe(42);
      expect(result.results.c).toEqual({ key: "val" });
    });
  });

  describe("部分失败降级（测试用例 5）", () => {
    it("data-ana 失败时该字段为 null，其他字段正常", async () => {
      const result = await orchestrate({
        parent: Promise.resolve({ id: "parent-001", name: "王家长" }),
        children: Promise.resolve([{ id: "student-001", name: "李同学" }]),
        analytics: Promise.reject(new Error("data-ana connection refused")),
      });

      expect(result.partial).toBe(true);
      expect(result.results.parent).toEqual({
        id: "parent-001",
        name: "王家长",
      });
      expect(result.results.children).toEqual([
        { id: "student-001", name: "李同学" },
      ]);
      expect(result.results.analytics).toBeNull();
      expect(result.failures).toHaveLength(1);
      expect(result.failures[0]!.key).toBe("analytics");
    });

    it("多个失败都记录在 failures 中", async () => {
      const result = await orchestrate({
        ok: Promise.resolve("ok"),
        fail1: Promise.reject(new Error("err1")),
        fail2: Promise.reject(new Error("err2")),
      });

      expect(result.partial).toBe(true);
      expect(result.failures).toHaveLength(2);
      expect(result.failures.map((f) => f.key)).toContain("fail1");
      expect(result.failures.map((f) => f.key)).toContain("fail2");
      expect(result.results.ok).toBe("ok");
      expect(result.results.fail1).toBeNull();
      expect(result.results.fail2).toBeNull();
    });
  });

  describe("全部失败", () => {
    it("所有字段为 null 且 partial=true", async () => {
      const result = await orchestrate({
        a: Promise.reject(new Error("err-a")),
        b: Promise.reject(new Error("err-b")),
      });

      expect(result.partial).toBe(true);
      expect(result.results.a).toBeNull();
      expect(result.results.b).toBeNull();
      expect(result.failures).toHaveLength(2);
    });
  });

  describe("空任务", () => {
    it("返回空结果且 partial=false", async () => {
      const result = await orchestrate({});

      expect(result.partial).toBe(false);
      expect(result.failures).toHaveLength(0);
      expect(Object.keys(result.results)).toHaveLength(0);
    });
  });

  describe("并行执行", () => {
    it("任务并行执行而非串行", async () => {
      const delay = (ms: number) => new Promise((r) => setTimeout(r, ms));
      const start = Date.now();

      await orchestrate({
        a: delay(100).then(() => "a"),
        b: delay(100).then(() => "b"),
        c: delay(100).then(() => "c"),
      });

      const elapsed = Date.now() - start;
      // 并行：总耗时约 100ms（而非 300ms）
      expect(elapsed).toBeLessThan(250);
    });
  });

  describe("failures 结构", () => {
    it("failure 包含 key 和 error", async () => {
      const error = new Error("test error");
      const result = await orchestrate({
        failing: Promise.reject(error),
      });

      expect(result.failures).toHaveLength(1);
      expect(result.failures[0]!.key).toBe("failing");
      expect(result.failures[0]!.error).toBe(error);
    });

    it("非 Error 类型的 rejection 也记录", async () => {
      const result = await orchestrate({
        failing: Promise.reject("string error"),
      });

      expect(result.failures).toHaveLength(1);
      expect(result.failures[0]!.error).toBe("string error");
    });
  });
});
