import { describe, expect, it } from "vitest";
import { buildLiveRunArtifact, buildRunArtifact, buildStatusArtifact } from "./reporting.mjs";

describe("runner reporting", () => {
  it("builds run artifacts", () => {
    const results = [
      {
        name: "api",
        failed: false,
        skipped: false,
        suiteCount: 1,
        completedSuiteCount: 1,
        skippedSuiteCount: 0,
        failedSuiteCount: 0,
        totalFileCount: 3,
        completedFileCount: 3,
        passedFileCount: 3,
        failedFileCount: 0,
        skippedFileCount: 0,
        notRunFileCount: 0,
        durationMs: 1200,
        totalTaskDurationMs: 2400,
        dbBackend: "local",
        suites: [],
        errors: [],
      },
      {
        name: "frontend",
        failed: false,
        skipped: true,
        suiteCount: 0,
        completedSuiteCount: 0,
        skippedSuiteCount: 0,
        failedSuiteCount: 0,
        totalFileCount: 0,
        completedFileCount: 0,
        passedFileCount: 0,
        failedFileCount: 0,
        skippedFileCount: 0,
        notRunFileCount: 0,
        durationMs: 0,
        totalTaskDurationMs: 0,
        dbBackend: null,
        suites: [],
        errors: [],
      },
    ];

    const artifact = buildRunArtifact({
      productDir: "/tmp/my-product",
      results,
      startedAt: 1000,
      finishedAt: 4000,
      execution: {
        workers: 2,
        fileTimeoutSeconds: 60,
      },
      workerCount: 1,
      runtimeInstanceCount: 2,
      typeValues: ["all"],
      suiteSelectors: [],
      fileNames: [],
      shard: null,
      serviceFilter: null,
      scenarioSeed: "demo-seed",
      metadata: {
        git: {
          branch: "main",
          commitSha: "abc",
          repoRoot: "/tmp",
        },
        host: {
          hostname: "local",
          username: "dev",
        },
        testkitVersion: "0.1.17",
      },
      summarizeDbBackend: () => "local",
    });

    expect(artifact.product.name).toBe("my-product");
    expect(artifact.schemaVersion).toBe(8);
    expect(artifact.run).toMatchObject({
      workers: 2,
      fileTimeoutSeconds: 60,
      workerCount: 1,
      runtimeInstanceCount: 2,
      scenarioSeed: "demo-seed",
    });
    expect(artifact.summary.services).toEqual({
      total: 1,
      passed: 1,
      failed: 0,
      skipped: 0,
    });
    expect(artifact.summary.suites).toEqual({
      total: 1,
      completed: 1,
      passed: 1,
      failed: 0,
      skipped: 0,
    });
    expect(artifact.summary.files).toEqual({
      total: 3,
      passed: 3,
      failed: 0,
      skipped: 0,
      notRun: 0,
    });
    expect(artifact.services[0].durationMs).toBe(1200);
    expect(artifact.services[0].totalTaskDurationMs).toBe(2400);
    expect(artifact.logs).toEqual({
      services: [],
      setup: [],
    });
    expect(artifact.setup).toEqual({
      operations: [],
    });
  });

  it("builds live run artifacts with running status and setup details", () => {
    const artifact = buildLiveRunArtifact({
      productDir: "/tmp/my-product",
      results: [],
      startedAt: 1_000,
      updatedAt: 2_000,
      execution: {
        workers: 2,
        fileTimeoutSeconds: 60,
      },
      workerCount: 1,
      runtimeInstanceCount: 1,
      runtimeStats: [],
      typeValues: ["int"],
      suiteSelectors: [],
      fileNames: [],
      shard: null,
      serviceFilter: null,
      metadata: {
        git: {
          branch: "main",
          commitSha: "abc",
          repoRoot: "/tmp",
        },
        host: {
          hostname: "local",
          username: "dev",
        },
        testkitVersion: "0.1.54",
      },
      summarizeDbBackend: () => "local",
      serviceLogs: [],
      setupLogs: [
        {
          serviceName: "api",
          runtimeLabel: "api",
          stage: "runtime:prepare",
          path: ".testkit/results/setup/api__api__runtime-prepare.log",
        },
      ],
      setupOperations: [
        {
          id: "setup-1",
          serviceName: "api",
          runtimeLabel: "api",
          stage: "runtime:prepare",
          kind: "runtime-prepare",
          summary: "runtime prepare",
          parentId: null,
          status: "running",
          startedAt: "1970-01-01T00:00:01.000Z",
          finishedAt: null,
          durationMs: null,
          error: null,
          logRef: {
            path: ".testkit/results/setup/api__api__runtime-prepare.log",
            stage: "runtime:prepare",
          },
        },
      ],
    });

    expect(artifact.run.status).toBe("running");
    expect(artifact.logs.setup).toEqual([
      {
        serviceName: "api",
        runtimeLabel: "api",
        stage: "runtime:prepare",
        path: ".testkit/results/setup/api__api__runtime-prepare.log",
      },
    ]);
    expect(artifact.setup.operations).toHaveLength(1);
  });

  it("builds deterministic status artifacts", () => {
    const status = buildStatusArtifact({
      productDir: "/tmp/my-product",
      results: [
        {
          name: "api",
          failed: true,
          skipped: false,
          suites: [
            {
              name: "health",
              type: "int",
              framework: "k6",
              files: [
                { path: "tests/api/integration/a.int.testkit.ts", status: "passed" },
                {
                  path: "tests/api/integration/b.int.testkit.ts",
                  status: "skipped",
                  reason: "Billing is stubbed",
                },
              ],
            },
          ],
        },
      ],
      typeValues: ["int"],
      suiteSelectors: [{ kind: "plain", name: "health", raw: "health" }],
      fileNames: ["tests/api/integration/b.int.testkit.ts"],
      shard: null,
      serviceFilter: "api",
      scenarioSeed: "demo-seed",
      metadata: {
        git: {
          branch: "main",
          commitSha: "abc123",
        },
        testkitVersion: "0.1.20",
      },
    });

    expect(status).toEqual({
      schemaVersion: 6,
      source: "testkit",
      notice: "Generated file. Do not edit manually.",
      product: {
        name: "my-product",
      },
      git: {
        branch: "main",
        commitSha: "abc123",
      },
      testkitVersion: "0.1.20",
      scope: {
        types: ["int"],
        suiteSelectors: ["health"],
        fileNames: ["tests/api/integration/b.int.testkit.ts"],
        shard: null,
        serviceFilter: "api",
        scenarioSeed: "demo-seed",
        isFullRun: false,
      },
      summary: {
        services: {
          total: 1,
          passed: 0,
          failed: 1,
          skipped: 0,
        },
        tests: {
          total: 2,
          passed: 1,
          failed: 0,
          skipped: 1,
          notRun: 0,
        },
      },
      tests: [
        {
          service: "api",
          type: "int",
          path: "tests/api/integration/a.int.testkit.ts",
          status: "passed",
        },
        {
          service: "api",
          type: "int",
          path: "tests/api/integration/b.int.testkit.ts",
          status: "skipped",
          reason: "Billing is stubbed",
        },
      ],
    });
  });

  it("marks unfiltered status artifacts as full runs", () => {
    const status = buildStatusArtifact({
      productDir: "/tmp/my-product",
      results: [],
      typeValues: ["all"],
      suiteSelectors: [],
      fileNames: [],
      shard: null,
      serviceFilter: null,
      scenarioSeed: null,
      metadata: {
        git: {
          branch: "main",
          commitSha: "abc123",
        },
        testkitVersion: "0.1.20",
      },
    });

    expect(status.scope.isFullRun).toBe(true);
  });
});
