import { describe, expect, it } from "vitest";
import { postProcessAllBrands } from "../../src/grl/post/index.js";
import {
  importBrandProgram,
  parseAbbRapid,
  parseFanucLs,
  parseKukaKrl
} from "../../src/importers/index.js";
import { applyPatch, createOlpProject, validateOlpProject } from "../../src/olp/index.js";

const ABB_MOD = `MODULE PickPlace
  PERS tooldata gripper:=[TRUE,[[0,0,100],[1,0,0,0]],[1,[0,0,0],[1,0,0,0],0,0,0]];
  CONST robtarget pPick := [[500,0,100],[1,0,0,0],[0,0,0,0],[9E9,9E9,9E9,9E9,9E9,9E9]];
  CONST robtarget pMid := [[550,50,100],[1,0,0,0],[0,0,0,0],[9E9,9E9,9E9,9E9,9E9,9E9]];
  CONST robtarget pPlace := [[600,0,100],[1,0,0,0],[0,0,0,0],[9E9,9E9,9E9,9E9,9E9,9E9]];
  CONST jointtarget jHome := [[0,0,0,0,0,0],[9E9,9E9,9E9,9E9,9E9,9E9]];
  PROC main()
    MoveJ jHome,v100,fine,gripper;
    MoveL pPick,v200,z10,gripper;
    MoveC pMid,pPlace,v200,fine,gripper;
  ENDPROC
ENDMODULE`;

const KUKA_SRC = `DEF PickPlace()
  $TOOL = TOOL_DATA[1]
  $BASE = BASE_DATA[2]
  PTP HOME
  LIN XPICK
  CIRC XMID, XPLACE
END`;

const KUKA_DAT = `DEFDAT PickPlace
DECL E6AXIS HOME={A1 0,A2 0,A3 0,A4 0,A5 0,A6 0,E1 0}
DECL E6POS XPICK={X 500,Y 0,Z 100,A 0,B 0,C 0,S 2,T 35,E1 0}
DECL E6POS XMID={X 550,Y 50,Z 100,A 0,B 0,C 0,S 2,T 35,E1 0}
DECL E6POS XPLACE={X 600,Y 0,Z 100,A 0,B 0,C 0,S 2,T 35,E1 0}
ENDDAT`;

const FANUC_LS = `/PROG PICKPLACE
/MN
   1:J P[1] 50% FINE ;
   2:L P[2] 200mm/sec CNT10 ;
   3:C P[3] P[4] 200mm/sec FINE ;
/POS
P[1]{
   X = 0.000  mm, Y = 0.000  mm, Z = 0.000  mm,
   W = 0.000 deg, P = 0.000 deg, R = 0.000 deg
};
P[2]{
   X = 500.000  mm, Y = 0.000  mm, Z = 100.000  mm,
   W = 0.000 deg, P = 0.000 deg, R = 0.000 deg
};
P[3]{
   X = 550.000  mm, Y = 50.000  mm, Z = 100.000  mm,
   W = 0.000 deg, P = 0.000 deg, R = 0.000 deg
};
P[4]{
   X = 600.000  mm, Y = 0.000  mm, Z = 100.000  mm,
   W = 0.000 deg, P = 0.000 deg, R = 0.000 deg
};
/END`;

describe("brand import MVP", () => {
  it("parses ABB RAPID targets, motions, tool hints, and produces runnable GRL", () => {
    const parsed = parseAbbRapid([{ name: "PickPlace.mod", text: ABB_MOD }]);
    const result = importBrandProgram("abb", [{ name: "PickPlace.mod", text: ABB_MOD }], {
      projectName: "AbbImport",
      generatedAt: "2026-06-27T00:00:00.000Z"
    });
    const patched = applyPatch(createOlpProject({ id: "abb_import", name: "AbbImport" }), result.patch);

    expect(parsed.targets.map((target) => target.name)).toEqual(["pPick", "pMid", "pPlace", "jHome"]);
    expect(parsed.points.map((point) => [point.motion, point.targetId, point.viaTargetId])).toEqual([
      ["movej", "target_jHome", undefined],
      ["movel", "target_pPick", undefined],
      ["movec", "target_pPlace", "target_pMid"]
    ]);
    expect(validateOlpProject(patched).ok).toBe(true);
    expect(result.grl).toContain("operation abb_operation");
    expect(result.ir.paths[0]?.motions.map((motion) => motion.kind)).toEqual(["MOVEJ", "MOVEL", "MOVEC"]);
    expect(result.report.status).toBe("warn");
    expect(result.report.sections.find((section) => section.name === "import")?.diagnostics.map((diagnostic) => diagnostic.code)).toEqual([
      "IMPORT_TARGETS",
      "IMPORT_MOTIONS",
      "IMPORT_TOOL_DETECTED"
    ]);
    expect(result.importReport).toEqual([
      expect.objectContaining({ code: "IMPORT_TOOL_DETECTED", severity: "info" })
    ]);
    expect(postProcessAllBrands(result.ir).outputs.abb.text).toContain("MoveC pMid,pPlace");
  });

  it("parses KUKA KRL src/dat movement and frame/tool hints", () => {
    const parsed = parseKukaKrl([
      { name: "PickPlace.src", text: KUKA_SRC },
      { name: "PickPlace.dat", text: KUKA_DAT }
    ]);
    const result = importBrandProgram("kuka", [
      { name: "PickPlace.src", text: KUKA_SRC },
      { name: "PickPlace.dat", text: KUKA_DAT }
    ], {
      projectName: "KukaImport",
      generatedAt: "2026-06-27T00:00:00.000Z"
    });

    expect(parsed.targets.map((target) => target.name).sort()).toEqual(["HOME", "XMID", "XPICK", "XPLACE"]);
    expect(result.parsed.path.points.map((point) => point.motion)).toEqual(["movej", "movel", "movec"]);
    expect(result.report.sections.find((section) => section.name === "import")?.diagnostics.map((diagnostic) => diagnostic.code)).toEqual([
      "IMPORT_TARGETS",
      "IMPORT_MOTIONS",
      "IMPORT_TOOL_DETECTED",
      "IMPORT_FRAME_DETECTED"
    ]);
    expect(result.report.status).toBe("warn");
    expect(postProcessAllBrands(result.ir).outputs.kuka.text).toContain("CIRC XMID, XPLACE");
  });

  it("parses FANUC LS P/PR style positions and circular moves", () => {
    const parsed = parseFanucLs([{ name: "PICKPLACE.ls", text: FANUC_LS }]);
    const result = importBrandProgram("fanuc", [{ name: "PICKPLACE.ls", text: FANUC_LS }], {
      projectName: "FanucImport",
      generatedAt: "2026-06-27T00:00:00.000Z"
    });

    expect(parsed.targets.map((target) => target.name)).toEqual(["P1", "P2", "P3", "P4"]);
    expect(result.patch).toEqual(expect.arrayContaining([
      expect.objectContaining({ op: "add", path: "/targets/-" }),
      expect.objectContaining({ op: "add", path: "/paths/-" }),
      expect.objectContaining({ op: "add", path: "/operations/-" })
    ]));
    expect(result.grl).toContain("module FanucImport");
    expect(result.parsed.path.points.map((point) => [point.motion, point.targetId, point.viaTargetId])).toEqual([
      ["movej", "target_P1", undefined],
      ["movel", "target_P2", undefined],
      ["movec", "target_P4", "target_P3"]
    ]);
    expect(result.ir.operations[0]).toMatchObject({
      operationId: "fanuc_operation",
      kind: "imported_program",
      pathId: "fanuc_path"
    });
    expect(postProcessAllBrands(result.ir).outputs.fanuc.text).toContain("C P3 P4");
  });
});
