// tests/build/icons-present.test.ts — Plan 01-12 Wave 0 RED unit test.
//
// Asserts that icons/icon{16,48,128}.png are rasterized from the Loom
// brand mark via rsvg-convert (Wave 2 Task 1) — replacing the Bug A
// placeholders (16-bit/color RGB) with 8-bit/color RGBA.
//
// Polarity at Wave 0 land:
//   - Dimension + size FLOOR cases: GREEN today (placeholders are at
//     correct dims + clear size floors). Stay GREEN after Wave 2.
//   - Color-type RGBA case: RED today (placeholders are color-type 2 =
//     RGB). Flips GREEN after Wave 2 (rsvg-convert default output is
//     8-bit/color RGBA, color-type 6).
//
// PNG header layout per ISO/IEC 15948 §11.2.2:
//   - Bytes 0-7: signature 89 50 4E 47 0D 0A 1A 0A
//   - Bytes 8-11: chunk length (big-endian uint32)
//   - Bytes 12-15: chunk type 'IHDR' (49 48 44 52)
//   - Bytes 16-19: width (big-endian uint32)
//   - Bytes 20-23: height (big-endian uint32)
//   - Byte 24:    bit depth (8 or 16 for our cases)
//   - Byte 25:    color type — 2=RGB, 6=RGBA (load-bearing for RED→GREEN flip)
//
// References:
//   - RESEARCH §3 (verified locally: rsvg-convert defaults to 8-bit RGBA)
//   - assets-spec.md (Chrome imageUtil silent-rejection FLOORs)
//   - Plan 01-13 harness A9 (icon-size floor at UAT-time)

import { describe, expect, it } from 'vitest';
import { existsSync, openSync, readSync, closeSync, statSync } from 'node:fs';
import { resolve as resolvePath } from 'node:path';

const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
const COLOR_TYPE_RGBA = 6;

interface IconSpec {
  readonly size: number;
  readonly sizeFloorBytes: number;
}

/** Per assets-spec.md Chrome imageUtil silent-rejection thresholds. */
const ICON_SPECS: ReadonlyArray<IconSpec> = [
  { size: 16, sizeFloorBytes: 200 },
  { size: 48, sizeFloorBytes: 500 },
  { size: 128, sizeFloorBytes: 1024 },
];

/**
 * Read the first N bytes of a file synchronously. Used to parse the PNG
 * header without slurping the whole file. Returns a Buffer of length N
 * (zero-padded if the file is shorter, which only happens on a corrupt
 * non-PNG file we want to fail loudly on anyway).
 */
function readHead(filePath: string, n: number): Buffer {
  const buf = Buffer.alloc(n);
  const fd = openSync(filePath, 'r');
  try {
    readSync(fd, buf, 0, n, 0);
  } finally {
    closeSync(fd);
  }
  return buf;
}

/** Read big-endian uint32 at offset; ISO/IEC 15948 §7 mandates network byte order. */
function readU32BE(buf: Buffer, offset: number): number {
  return buf.readUInt32BE(offset);
}

describe('Plan 01-12: icons rasterized from Loom mark (RGBA, 8-bit, clearing imageUtil FLOORs)', () => {
  for (const spec of ICON_SPECS) {
    const iconPath = resolvePath(process.cwd(), `icons/icon${spec.size}.png`);

    describe(`icons/icon${spec.size}.png (${spec.size}×${spec.size})`, () => {
      it('exists at icons/iconN.png', () => {
        expect(existsSync(iconPath), `Expected ${iconPath}`).toBe(true);
      });

      it(`size >= ${spec.sizeFloorBytes} bytes (Chrome imageUtil floor)`, () => {
        const size = statSync(iconPath).size;
        expect(
          size,
          `icon${spec.size}.png is ${size} B; need >= ${spec.sizeFloorBytes} B to clear Chrome imageUtil floor`,
        ).toBeGreaterThanOrEqual(spec.sizeFloorBytes);
      });

      it('PNG signature (first 8 bytes match \\x89PNG\\r\\n\\x1a\\n)', () => {
        const head = readHead(iconPath, 8);
        expect(
          head.equals(PNG_SIGNATURE),
          `Expected PNG signature; got ${head.toString('hex')}`,
        ).toBe(true);
      });

      it(`dimensions === ${spec.size}×${spec.size} (IHDR offset 16-23, big-endian uint32)`, () => {
        const head = readHead(iconPath, 32);
        const width = readU32BE(head, 16);
        const height = readU32BE(head, 20);
        expect(width, `icon${spec.size}.png width`).toBe(spec.size);
        expect(height, `icon${spec.size}.png height`).toBe(spec.size);
      });

      it('color-type byte (IHDR offset 25) === 6 (RGBA — RED until Wave 2 overwrites placeholder)', () => {
        const head = readHead(iconPath, 32);
        const colorType = head[25];
        expect(
          colorType,
          colorType === COLOR_TYPE_RGBA
            ? 'unreachable'
            : `icon${spec.size}.png color-type=${colorType}; expected 6 (RGBA). ` +
              `Placeholder PNGs are color-type 2 (RGB). RED until Wave 2 Task 1 ` +
              `rasterizes via rsvg-convert (default output is 8-bit/color RGBA per RESEARCH §3).`,
        ).toBe(COLOR_TYPE_RGBA);
      });
    });
  }
});
