import {
  buildSpritesPayloadFromImagesPayload,
  buildTilesPayloadFromImagesPayload,
  mergeImagesPayloadWithTilesPayload,
  normalizeImageRecordForSave,
  normalizeImagesPayloadForSave,
  normalizeTileRecordForSave,
} from "./graphicsPayload";
import type { JsonObject, JsonValue } from "../contracts/json";
import { getSpriteRows } from "../graphics/rowEncoding";

describe("graphicsPayload", () => {
  it("normalizes tile records with padded rows and compatibility symbols", () => {
    const result = normalizeTileRecordForSave({
      id: "tile_grass",
      rows: ["A", "BC", "DROP"],
      width: 2,
      height: 2,
    });

    expect(result).toEqual(expect.objectContaining({
      id: "tile_grass",
      symbol: "t",
      rows: ["A.", "BC"],
      width: 2,
      height: 2,
    }));
  });

  it("normalizes image records into frame-based storage while preserving tile compatibility", () => {
    const result = normalizeImageRecordForSave({
      id: "tile_tree",
      roles: ["tile", "sprite", "other", "tile"],
      rows: ["A", "BC"],
      width: 2,
      height: 2,
      speed: -10,
      playback: "invalid",
      tileSymbol: "$",
    });

    expect(result.rows).toBeUndefined();
    expect(result.symbol).toBeUndefined();
    expect(result.graphicRole).toBeUndefined();
    expect(result.roles).toEqual(["tile", "sprite"]);
    expect(result.defaultFrame).toBe("frame_0");
    expect(result.speed).toBe(0);
    expect(result.playback).toBe("normal");
    expect(result.tileSymbol).toBe("$");
    expect(result.frames).toEqual([
      expect.objectContaining({
        id: "frame_0",
        rows: ["A.", "BC"],
      }),
    ]);
  });

  it("resolves sprite rows from the default enabled frame", () => {
    const record: JsonObject = {
      defaultFrame: "walk_1",
      frames: [
        { id: "idle", rows: ["II"], enabled: true },
        { id: "walk_1", rows: ["WW"], enabled: true },
        { id: "disabled", rows: ["DD"], enabled: false },
      ],
    };

    expect(getSpriteRows(record)).toEqual(["WW"]);
  });

  it("normalizes image payload arrays without changing non-record entries", () => {
    const payload: JsonValue = {
      schemaVersion: 1,
      images: [
        {
          id: "sprite_hero",
          roles: ["sprite"],
          rows: ["X"],
        },
        "leave-me-alone",
      ],
    };

    expect(normalizeImagesPayloadForSave(payload)).toEqual({
      schemaVersion: 1,
      images: [
        expect.objectContaining({
          id: "sprite_hero",
          roles: ["sprite"],
          defaultFrame: "frame_0",
        }),
        "leave-me-alone",
      ],
    });
  });

  it("projects tiles and sprites from images while preserving current compatibility behavior", () => {
    const imagesPayload: JsonValue = {
      schemaVersion: 1,
      images: [
        {
          id: "tile_grass",
          roles: ["tile"],
          tileSymbol: "G",
          width: 2,
          height: 2,
          frames: [{ id: "frame_0", rows: ["AA", "BB"] }],
        },
        {
          id: "sprite_hero",
          roles: ["sprite"],
          width: 1,
          height: 1,
          frames: [{ id: "frame_0", rows: ["H"] }],
        },
      ],
    };

    expect(buildTilesPayloadFromImagesPayload(imagesPayload)).toEqual({
      schemaVersion: 1,
      tiles: [expect.objectContaining({ id: "tile_grass", symbol: "G", rows: ["AA", "BB"] })],
    });
    expect(buildSpritesPayloadFromImagesPayload(imagesPayload)).toEqual({
      schemaVersion: 1,
      sprites: [expect.objectContaining({ id: "sprite_hero", rows: ["H"] })],
    });
  });

  it("merges tile payloads into images and removes tile role when a tile disappears", () => {
    const merged = mergeImagesPayloadWithTilesPayload(
      {
        schemaVersion: 1,
        images: [
          {
            id: "shared",
            roles: ["tile", "sprite"],
            tileSymbol: "S",
            frames: [{ id: "frame_0", rows: ["A"] }],
          },
        ],
      },
      {
        schemaVersion: 1,
        tiles: [],
      },
    );

    expect(merged).toEqual({
      schemaVersion: 1,
      images: [
        expect.objectContaining({
          id: "shared",
          roles: ["sprite"],
          tileSymbol: "",
        }),
      ],
    });
  });
});
