import { describe, expect, it } from "vitest";

import { createEditorStore } from "../../src/app/editor-store";
import { createUpsertEntityCommand } from "../../src/commands/upsert-entity-command";
import { createPointLightEntity, createSoundEmitterEntity, createSpotLightEntity, createTriggerVolumeEntity } from "../../src/entities/entity-instances";

describe("typed entity upsert command", () => {
  it("places a Sound Emitter and restores the previous tool mode across undo and redo", () => {
    const store = createEditorStore();
    const soundEmitter = createSoundEmitterEntity({
      position: {
        x: 1,
        y: 2,
        z: 3
      },
      audioAssetId: null,
      volume: 0.5,
      refDistance: 5,
      maxDistance: 12
    });

    store.setToolMode("create");
    store.executeCommand(
      createUpsertEntityCommand({
        entity: soundEmitter,
        label: "Place sound emitter"
      })
    );

    expect(store.getState().toolMode).toBe("select");
    expect(store.getState().selection).toEqual({
      kind: "entities",
      ids: [soundEmitter.id]
    });
    expect(store.getState().document.entities[soundEmitter.id]).toEqual(soundEmitter);

    expect(store.undo()).toBe(true);
    expect(store.getState().toolMode).toBe("create");
    expect(store.getState().document.entities).toEqual({});

    expect(store.redo()).toBe(true);
    expect(store.getState().toolMode).toBe("select");
    expect(store.getState().document.entities[soundEmitter.id]).toEqual(soundEmitter);
  });

  it("places a Point Light and restores the previous tool mode across undo and redo", () => {
    const store = createEditorStore();
    const pointLight = createPointLightEntity({
      position: {
        x: 2,
        y: 3,
        z: 4
      },
      colorHex: "#ccddee",
      intensity: 1.5,
      distance: 9
    });

    store.setToolMode("create");
    store.executeCommand(
      createUpsertEntityCommand({
        entity: pointLight,
        label: "Place point light"
      })
    );

    expect(store.getState().toolMode).toBe("select");
    expect(store.getState().selection).toEqual({
      kind: "entities",
      ids: [pointLight.id]
    });
    expect(store.getState().document.entities[pointLight.id]).toEqual(pointLight);

    expect(store.undo()).toBe(true);
    expect(store.getState().toolMode).toBe("create");
    expect(store.getState().document.entities).toEqual({});

    expect(store.redo()).toBe(true);
    expect(store.getState().toolMode).toBe("select");
    expect(store.getState().document.entities[pointLight.id]).toEqual(pointLight);
  });

  it("updates an existing Trigger Volume without changing its entity id", () => {
    const store = createEditorStore();
    const triggerVolume = createTriggerVolumeEntity({
      id: "entity-trigger-main",
      size: {
        x: 2,
        y: 2,
        z: 2
      }
    });
    const movedTriggerVolume = createTriggerVolumeEntity({
      ...triggerVolume,
      position: {
        x: 4,
        y: 1,
        z: -2
      },
      size: {
        x: 3,
        y: 4,
        z: 5
      },
      triggerOnEnter: false,
      triggerOnExit: true
    });

    store.executeCommand(
      createUpsertEntityCommand({
        entity: triggerVolume,
        label: "Place trigger volume"
      })
    );
    store.setToolMode("create");
    store.executeCommand(
      createUpsertEntityCommand({
        entity: movedTriggerVolume,
        label: "Update trigger volume"
      })
    );

    expect(store.getState().toolMode).toBe("select");
    expect(store.getState().document.entities[triggerVolume.id]).toEqual(movedTriggerVolume);

    expect(store.undo()).toBe(true);
    expect(store.getState().toolMode).toBe("create");
    expect(store.getState().document.entities[triggerVolume.id]).toEqual(triggerVolume);

    expect(store.redo()).toBe(true);
    expect(store.getState().document.entities[triggerVolume.id]).toEqual(movedTriggerVolume);
  });

  it("updates an existing Spot Light without changing its entity id", () => {
    const store = createEditorStore();
    const spotLight = createSpotLightEntity({
      id: "entity-spot-main",
      position: {
        x: -3,
        y: 4,
        z: 2
      }
    });
    const movedSpotLight = createSpotLightEntity({
      ...spotLight,
      position: {
        x: 5,
        y: 6,
        z: -4
      },
      direction: {
        x: 0.5,
        y: -1,
        z: 0.25
      },
      colorHex: "#aaccee",
      intensity: 2.25,
      distance: 14,
      angleDegrees: 50
    });

    store.executeCommand(
      createUpsertEntityCommand({
        entity: spotLight,
        label: "Place spot light"
      })
    );
    store.setToolMode("create");
    store.executeCommand(
      createUpsertEntityCommand({
        entity: movedSpotLight,
        label: "Update spot light"
      })
    );

    expect(store.getState().toolMode).toBe("select");
    expect(store.getState().document.entities[spotLight.id]).toEqual(movedSpotLight);

    expect(store.undo()).toBe(true);
    expect(store.getState().toolMode).toBe("create");
    expect(store.getState().document.entities[spotLight.id]).toEqual(spotLight);

    expect(store.redo()).toBe(true);
    expect(store.getState().document.entities[spotLight.id]).toEqual(movedSpotLight);
  });
});
