import UPNG from "upng-js";

export interface GplEntry {
  name: string;
  r: number;
  g: number;
  b: number;
  a: number;
}

export interface TileGrid {
  cols: number;
  rows: number;
  tiles: Uint8Array;
}

export function parseGpl(text: string): GplEntry[] {
  const entries: GplEntry[] = [];
  for (const line of text.split("\n")) {
    const trimmed = line.trim();
    if (
      !trimmed ||
      trimmed.startsWith("GIMP") ||
      trimmed.startsWith("Channels") ||
      trimmed.startsWith("#")
    )
      continue;
    const match = trimmed.match(/^(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(.+)$/);
    if (!match) continue;
    entries.push({
      r: parseInt(match[1]),
      g: parseInt(match[2]),
      b: parseInt(match[3]),
      a: parseInt(match[4]),
      name: match[5].trim(),
    });
  }
  return entries;
}

export function decodeWorldMap(
  palette: GplEntry[],
  pngBuffer: ArrayBuffer,
  tileEnum: Record<string, number>,
): TileGrid {
  const enumNames = new Set(
    Object.keys(tileEnum).filter((k) => isNaN(Number(k))),
  );
  const paletteNames = new Set(palette.map((e) => e.name));

  for (const name of enumNames) {
    if (!paletteNames.has(name))
      throw new Error(`Enum member "${name}" has no matching palette entry`);
  }
  for (const name of paletteNames) {
    if (!enumNames.has(name))
      throw new Error(`Palette entry "${name}" has no matching enum member`);
  }

  const colorToTile = new Map<number, number>();
  for (const entry of palette) {
    const key = (entry.r << 24) | (entry.g << 16) | (entry.b << 8) | entry.a;
    colorToTile.set(key, tileEnum[entry.name]);
  }

  const img = UPNG.decode(pngBuffer);
  const rgba = new Uint8Array(UPNG.toRGBA8(img)[0]);
  const area = img.width * img.height;
  const tiles = new Uint8Array(area);

  for (let i = 0; i < area; i++) {
    const key =
      (rgba[i * 4] << 24) |
      (rgba[i * 4 + 1] << 16) |
      (rgba[i * 4 + 2] << 8) |
      rgba[i * 4 + 3];
    const tile = colorToTile.get(key);
    if (tile === undefined)
      throw new Error(
        `Pixel at index ${i} has no matching palette entry (RGBA ${rgba[i * 4]},${rgba[i * 4 + 1]},${rgba[i * 4 + 2]},${rgba[i * 4 + 3]})`,
      );
    tiles[i] = tile;
  }

  return { cols: img.width, rows: img.height, tiles };
}