import { describe, expect, it } from "vitest";
import type { TguPlanUi } from "../../model/timelineTypes";
import {
  addDownlink,
  addShoot,
  deleteWork,
  duplicateWork,
  mutate,
  redo,
  seedDraft,
  undo,
  updateWork
} from "./editorDraft";
import type { DraftHistory } from "./model/editorTypes";

const plan: TguPlanUi = {
  planId: "plan-1",
  spacecraftId: "56756",
  startTime: "2026-05-29T01:00:00Z",
  endTime: "2026-05-29T02:00:00Z",
  kppId: "KPP-1",
  status: "PLANNED",
  startMs: Date.parse("2026-05-29T01:00:00Z"),
  endMs: Date.parse("2026-05-29T02:00:00Z")
};

describe("editorDraft", () => {
  it("seeds a draft from the current API plan envelope when embedded works are absent", () => {
    expect(seedDraft(plan)).toEqual({
      planId: "plan-1",
      spacecraftId: "56756",
      works: [
        {
          id: "plan-1:plan-window",
          kind: "downlink",
          label: "План ТГУ · KPP-1",
          startMs: plan.startMs,
          endMs: plan.endMs,
          stationId: "KPP-1",
          origin: "plan"
        }
      ]
    });
  });

  it("adds shoot and downlink works with deterministic ids", () => {
    const draft = seedDraft(undefined, "56756");
    const withShoot = addShoot(draft, {
      id: "shoot-1",
      label: "Панхром. съёмка",
      modeId: "pan",
      startMs: 1000,
      endMs: 2000,
      target: { id: "target-1", name: "Цель A", lat: 55.7, lon: 37.6 }
    });
    const withDownlink = addDownlink(withShoot, {
      id: "downlink-1",
      label: "Сброс на НКПОР",
      startMs: 3000,
      endMs: 4000,
      station: { id: "KPP-1", name: "KPP-1" }
    });

    expect(withDownlink.works.map((work) => work.id)).toEqual(["shoot-1", "downlink-1"]);
    expect(withDownlink.works.every((work) => work.origin === "added" && work.isNew)).toBe(true);
  });

  it("keeps undo and redo stacks consistent across mutations", () => {
    const initial: DraftHistory = { draft: seedDraft(undefined, "56756"), past: [], future: [] };
    const changed = mutate(initial, (draft) =>
      addDownlink(draft, {
        id: "downlink-1",
        label: "Сброс",
        startMs: 1000,
        endMs: 2000,
        station: { id: "KPP-1", name: "KPP-1" }
      })
    );

    const undone = undo(changed);
    const redone = redo(undone);

    expect(changed.past).toHaveLength(1);
    expect(undone.draft.works).toHaveLength(0);
    expect(undone.future).toHaveLength(1);
    expect(redone.draft.works).toHaveLength(1);
    expect(redone.future).toHaveLength(0);
  });

  it("updates, duplicates and deletes works without generating ids internally", () => {
    const draft = seedDraft(plan);
    const updated = updateWork(draft, "plan-1:plan-window", { label: "Сеанс", startMs: plan.startMs + 60_000 });
    const duplicated = duplicateWork(updated, "plan-1:plan-window", "copy-1", 120_000);
    const deleted = deleteWork(duplicated, "plan-1:plan-window");

    expect(updated.works[0].label).toBe("Сеанс");
    expect(duplicated.works[1]).toMatchObject({
      id: "copy-1",
      startMs: updated.works[0].startMs + 120_000,
      endMs: updated.works[0].endMs + 120_000,
      origin: "added",
      isNew: true
    });
    expect(deleted.works.map((work) => work.id)).toEqual(["copy-1"]);
  });
});
