import { describe, expect, it } from "vitest";
import { postProcessBrand } from "../../src/grl/post/index.js";
import { parseGrl } from "../../src/grl/parser/index.js";
import { compileSemanticProgram } from "../../src/grl/semantic/index.js";
import { pathOperationToGrl, sampleOlpProject } from "../../src/olp/index.js";
import {
  calibrationSummary,
  createValidationReport,
  exportCustomerDeliveryPackage,
  exportValidationReportHtml,
  serializeDeliveryPackage,
  validateReportSchema
} from "../../src/reports/index.js";

const NOW = "2026-06-27T00:00:00.000Z";

describe("validation reports and customer delivery", () => {
  it("creates stable validation report sections for reachability, cycle, IO/Wait, post, import, and calibration", () => {
    const project = sampleOlpProject();
    const report = createValidationReport({
      id: "demo_validation",
      project,
      generatedAt: NOW,
      pathValidation: {
        ok: true,
        reachable: true,
        cycleTime: 4.2,
        segmentReports: [],
        diagnostics: []
      },
      ioWaitDiagnostics: [],
      postDiagnostics: [],
      importDiagnostics: [
        {
          severity: "info",
          code: "IMPORT_OK",
          message: "ABB import mapped to OLP",
          sourceMap: { file: "imports/PickPlace.mod", line: 8 }
        }
      ]
    });

    expect(validateReportSchema(report)).toEqual({ ok: true, issues: [] });
    expect(report.status).toBe("pass");
    expect(report.sections.map((section) => section.name)).toEqual([
      "reachability",
      "cycle_time",
      "io_wait",
      "post",
      "import",
      "collision",
      "calibration"
    ]);
    expect(report.sections.find((section) => section.name === "cycle_time")?.summary).toEqual({
      cycleTime: 4.2,
      trajectories: 0
    });
    expect(report.sourceMap).toEqual([
      {
        kind: "IMPORT_OK",
        id: "IMPORT_OK-0",
        file: "imports/PickPlace.mod",
        line: 8
      }
    ]);
  });

  it("exports openable HTML with summary, details, and source map payload", () => {
    const report = createValidationReport({
      id: "demo_validation",
      project: sampleOlpProject(),
      generatedAt: NOW,
      diagnostics: [
        {
          severity: "info",
          code: "REACH_OK",
          message: "pick target reachable",
          sourceMap: { file: "source/DemoCell.grl", line: 20 }
        }
      ]
    });
    const html = exportValidationReportHtml(report);

    expect(html).toContain("<!doctype html>");
    expect(html).toContain("Status: warn");
    expect(html).toContain("reachability");
    expect(html).toContain("source/DemoCell.grl");
    expect(html).toContain("validation-report-json");
  });

  it("exports customer delivery package with source, brand programs, IO map, reports, calibration, and trace", () => {
    const project = sampleOlpProject();
    const grl = pathOperationToGrl(project, "pick_op", { moduleName: "DemoCell" });
    project.programs.push(grl.program);
    const ir = compileSemanticProgram(parseGrl(grl.text), {
      startJoints: [0, 0, 0, 0, 0, 0],
      sampleTime: 0.004
    });
    const abb = postProcessBrand(ir, "abb");
    const report = createValidationReport({
      id: "demo_validation",
      project,
      generatedAt: NOW,
      postDiagnostics: abb.report.map((issue) => ({
        severity: issue.severity,
        code: issue.code,
        message: issue.message
      })),
      pathValidation: {
        ok: true,
        reachable: true,
        cycleTime: 4.2,
        segmentReports: [],
        diagnostics: []
      }
    });

    const pkg = exportCustomerDeliveryPackage({
      project,
      report,
      trace: { samples: ["t=0 movej home"] },
      brandPrograms: { [abb.filename]: abb.text },
      ioMap: { "io.do[1]": "vacuum" }
    });
    const serialized = serializeDeliveryPackage(pkg);

    expect(pkg.manifest).toEqual({
      sourcePrograms: ["source/pick_op_grl.grl"],
      brandPrograms: ["post/DemoCell.mod"],
      reports: ["reports/demo_validation.html", "reports/demo_validation.json"],
      calibrationFiles: ["calibration/calibrations.json"],
      traceFiles: ["trace/trace.json"],
      ioMaps: ["io/io_map.json"]
    });
    expect(pkg.files.map((file) => file.path)).toEqual([
      "calibration/calibrations.json",
      "io/io_map.json",
      "post/DemoCell.mod",
      "project/project.json",
      "reports/demo_validation.html",
      "reports/demo_validation.json",
      "source/pick_op_grl.grl",
      "trace/trace.json"
    ]);
    expect(serialized).toContain("\"format\": \"customer-delivery/0.1\"");
    expect(serialized).toContain("fnv1a32:");
    expect(calibrationSummary(project.calibrations)).toEqual({ tcp: 1 });
  });
});
