/**
 * Перекладка слотов модели на палитру сцены. Нужна после импорта .vox
 * (там слоты 1..N без отношения к сцене): цвет модели замещается цветом
 * сцены — точным совпадением hex или ближайшим по RGB-расстоянию
 * (детерминированно, при равенстве — меньший слот).
 */
import { hexToRgb } from '../voxel/grid';
import { decodeModel, encodeModel } from './format';
import type { VoxelPalette } from '../voxel/grid';
import type { VoxelModel } from './format';

export function remapSlots(model: VoxelModel, palette: VoxelPalette): VoxelModel {
    const scene = Object.entries(palette.colors).map(([slot, hex]) => ({
        slot: Number(slot),
        rgb: hexToRgb(hex),
    }));
    // слот модели → слот сцены
    const mapping = new Map<number, number>();
    for (const [slot, hex] of Object.entries(model.palette)) {
        const rgb = hexToRgb(hex);
        let best = scene[0], bestD = Infinity;
        for (const s of scene) {
            const d = (s.rgb[0] - rgb[0]) ** 2 + (s.rgb[1] - rgb[1]) ** 2 + (s.rgb[2] - rgb[2]) ** 2;
            if (d < bestD || (best && d === bestD && s.slot < best.slot)) { bestD = d; best = s; }
        }
        if (best) mapping.set(Number(slot), best.slot); // пустая палитра — слот не перекладывается
    }

    const grid = decodeModel(model);
    for (let i = 0; i < grid.data.length; i++) {
        const b = grid.data[i];
        if (b !== 0) grid.data[i] = mapping.get(b) ?? b;
    }
    // палитра результата — занятые слоты сцены с их hex
    const used = new Set(grid.data.filter((b) => b !== 0));
    const out = Object.fromEntries(
        [...used].map((slot) => [slot, palette.colors[slot]]),
    );
    return encodeModel(grid, out);
}