/**
 * Structural checks: door tiles on maps must be walkable (obstacle GID 0).
 * Regression: setO(x,y,0) used to write GID 1 and block exits.
 */
import { describe, it, expect } from 'vitest';
import house from '../../public/assets/maps/house.json';
import plaza from '../../public/assets/maps/plaza.json';
import bakery from '../../public/assets/maps/bakery.json';
import shop from '../../public/assets/maps/shop.json';
import clinic from '../../public/assets/maps/clinic.json';
import lake from '../../public/assets/maps/lake.json';
import field from '../../public/assets/maps/field.json';
import well from '../../public/assets/maps/well.json';
import fog from '../../public/assets/maps/fog.json';

type TiledMap = {
  width: number;
  height: number;
  layers: Array<{
    name: string;
    type: string;
    data?: number[];
    objects?: Array<{
      type: string;
      x: number;
      y: number;
      width?: number;
      height?: number;
      properties?: Array<{ name: string; value: unknown }>;
    }>;
  }>;
};

function doorTilesClear(map: TiledMap, name: string): void {
  const obs = map.layers.find((l) => l.name === 'obstacles');
  const objs = map.layers.find((l) => l.name === 'objects');
  expect(obs?.data, `${name} obstacles`).toBeDefined();
  expect(objs?.objects, `${name} objects`).toBeDefined();
  const doors = objs!.objects!.filter((o) => o.type === 'door');
  expect(doors.length, `${name} door count`).toBeGreaterThan(0);
  for (const d of doors) {
    const tx = Math.floor((d.x + (d.width || 16) / 2) / 16);
    const ty = Math.floor((d.y + (d.height || 16) / 2) / 16);
    const gid = obs!.data![ty * map.width + tx];
    expect(gid, `${name} door at tile (${tx},${ty}) must be walkable GID 0`).toBe(0);
  }
}

describe('map doors are walkable', () => {
  const maps: [string, TiledMap][] = [
    ['house', house as TiledMap],
    ['plaza', plaza as TiledMap],
    ['bakery', bakery as TiledMap],
    ['shop', shop as TiledMap],
    ['clinic', clinic as TiledMap],
    ['lake', lake as TiledMap],
    ['field', field as TiledMap],
    ['well', well as TiledMap],
    ['fog', fog as TiledMap],
  ];

  for (const [name, map] of maps) {
    it(`${name}: obstacle under each door is 0`, () => {
      doorTilesClear(map, name);
    });
  }

  it('house has doors targeting PlazaScene', () => {
    const map = house as TiledMap;
    const objs = map.layers.find((l) => l.name === 'objects')!.objects!;
    const doors = objs.filter((o) => o.type === 'door');
    expect(doors.length).toBeGreaterThanOrEqual(1);
    for (const d of doors) {
      const target = d.properties?.find((p) => p.name === 'target')?.value;
      expect(target).toBe('PlazaScene');
    }
  });
});
