import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';
import { encodeMap, parseMap } from '@rpg/engine';
import {
    buildMeadowsMap,
    buildPondsMap,
    buildZvenetsMap,
    buildHouseElderMap,
    buildShopMap
} from '../../src/data/map';

/**
 * Генератор карт-файлов: `npm run maps` (vitest run apps/game/tools/maps/gen.test.ts).
 * Карты строятся из data/map.ts (единый источник истины), пакуются в RLE
 * через движковый encodeMap и пишутся в apps/game/assets/maps/*.map.
 * Здесь же проверяется обратная распаковка: parseMap должен вернуть карту
 * попиксельно равную исходной.
 */

const here = dirname(fileURLToPath(import.meta.url));
const outDir = resolve(here, '../../assets/maps');

const MAPS: Record<string, ReturnType<typeof buildMeadowsMap>> = {
    meadows: buildMeadowsMap(),
    ponds: buildPondsMap(),
    zvenets: buildZvenetsMap(),
    house_elder: buildHouseElderMap(),
    shop: buildShopMap()
};

describe('карты-файлы на диске равны генераторам (fresh)', () => {
    for (const [id, data] of Object.entries(MAPS)) {
        it(`${id}.map не разъехался с генератором (npm run maps лечит)`, () => {
            const path = resolve(outDir, `${id}.map`);
            const onDisk = JSON.parse(readFileSync(path, 'utf8'));
            expect(onDisk).toEqual(encodeMap(data));
        });
    }
});

describe('генерация карт-файлов (rpg-map, RLE)', () => {
    for (const [id, data] of Object.entries(MAPS)) {
        it(`${id}: encode -> файл -> parse восстанавливает карту`, () => {
            const file = encodeMap(data);
            const back = parseMap(JSON.parse(JSON.stringify(file)));

            expect(back.width).toBe(data.width);
            expect(back.height).toBe(data.height);
            expect(back.blocked).toEqual(data.blocked);
            expect(back.tiles).toEqual(data.tiles);
            expect(back.tall).toEqual(data.tall);

            mkdirSync(outDir, { recursive: true });
            const path = resolve(outDir, `${id}.map`);
            writeFileSync(path, JSON.stringify(file));
        });
    }

    it('RLE реально сжимает карты', () => {
        for (const [id, data] of Object.entries(MAPS)) {
            const file = encodeMap(data);
            const pairs = file.tiles as [number, number][];
            // Серий меньше, чем тайлов: RLE что-то ужал, несмотря на пятнистость
            expect(pairs.length).toBeLessThan(data.tiles.length);
            expect(file.encoding).toBe('rle');
            expect(id.length).toBeGreaterThan(0);
        }
    });
});