// SKITTERDOME's Leveled adapter: maps the generic LevelDoc (schema v2) onto
// the game's LevelData runtime model, and wires the shared editor to the
// three.js editor camera.
import type { Game } from './game';
import { Cell, LevelData, defaultLevel as defaultLevelData, parseLevel, LS_KEY } from './level';
import type { DocSpec, EntityDef, LevelDoc, LeveledAdapter } from './leveled/types';

const ENTITIES: EntityDef[] = [
  {
    type: 'wall', label: 'Wall', hint: 'blocks bots + lasers',
    icon: '#3c4356', multiple: true, paint: true, layer: 2,
    blockedBy: ['spawn'], displaces: ['enemy', 'turret'],
  },
  {
    type: 'floor-glow', label: 'Floor glow', hint: 'paint the ground',
    icon: '#c22413', multiple: true, paint: true, layer: 1,
  },
  {
    type: 'spawn', label: 'Player spawn', hint: 'only one — moves it',
    icon: 'radial-gradient(circle, #5fe0ff 35%, #103040 70%)', round: true,
    multiple: false, permanent: true, layer: 5,
    displaces: ['wall', 'enemy', 'turret'],
  },
  {
    type: 'enemy', label: 'Enemy bot', hint: 'spider with a grudge',
    icon: 'radial-gradient(circle, #ff8a3c 35%, #3a2018 70%)', round: true,
    multiple: true, layer: 4,
    blockedBy: ['spawn', 'wall'], displaces: ['turret'],
  },
  {
    type: 'turret', label: 'Turret', hint: 'stationary, auto-fires',
    icon: 'radial-gradient(circle, #ffaa22 30%, #3a3f4d 36%)',
    multiple: true, layer: 3,
    blockedBy: ['spawn', 'wall'], displaces: ['enemy'],
  },
  {
    type: 'gigabot', label: 'Gigabot', hint: 'huge, slow, rocket volleys',
    icon: 'radial-gradient(circle, #ff3030 40%, #401414 75%)', round: true,
    multiple: true, layer: 4,
    blockedBy: ['spawn', 'wall', 'tree'], displaces: ['enemy', 'turret'],
  },
  {
    type: 'tree', label: 'Tree of Life', hint: 'objective — only one',
    icon: 'radial-gradient(circle, #5dff9a 30%, #0e3a22 75%)', round: true,
    multiple: false, layer: 5,
    blockedBy: ['spawn', 'wall'], displaces: ['enemy', 'turret', 'gigabot'],
  },
];

/** Generic doc -> the game's runtime LevelData. */
export function docToLevel(doc: LevelDoc): LevelData {
  const lvl: LevelData = {
    version: 1,
    size: [doc.size[0], doc.size[1]],
    playerSpawn: [1, 1],
    walls: [],
    enemies: [],
    turrets: [],
    gigabots: [],
    accents: [],
    tree: null,
  };
  for (const e of doc.entities) {
    const c: Cell = [e.x, e.y];
    switch (e.type) {
      case 'wall': lvl.walls.push(c); break;
      case 'floor-glow': lvl.accents.push(c); break;
      case 'enemy': lvl.enemies.push(c); break;
      case 'turret': lvl.turrets.push(c); break;
      case 'gigabot': lvl.gigabots.push(c); break;
      case 'tree': lvl.tree = c; break;
      case 'spawn': lvl.playerSpawn = c; break;
    }
  }
  return lvl;
}

/** The game's LevelData -> generic doc (also the v1 -> v2 migration step). */
export function levelToDoc(lvl: LevelData): LevelDoc {
  const entities: LevelDoc['entities'] = [];
  for (const [x, y] of lvl.walls) entities.push({ type: 'wall', x, y });
  for (const [x, y] of lvl.accents) entities.push({ type: 'floor-glow', x, y });
  for (const [x, y] of lvl.enemies) entities.push({ type: 'enemy', x, y });
  for (const [x, y] of lvl.turrets) entities.push({ type: 'turret', x, y });
  for (const [x, y] of lvl.gigabots) entities.push({ type: 'gigabot', x, y });
  if (lvl.tree) entities.push({ type: 'tree', x: lvl.tree[0], y: lvl.tree[1] });
  entities.push({ type: 'spawn', x: lvl.playerSpawn[0], y: lvl.playerSpawn[1] });
  return {
    version: 2,
    gameType: 'skitterdome',
    size: [lvl.size[0], lvl.size[1]],
    entities,
  };
}

/** Doc shape/validation spec — usable before the Game instance exists. */
export const skitterSpec: DocSpec = {
  gameType: 'skitterdome',
  minSize: [4, 4],
  maxSize: [64, 64],
  entities: ENTITIES,
  migrate(raw: unknown): LevelDoc | null {
    // v1: { version: 1, size, playerSpawn, walls, enemies, turrets, accents }
    if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null;
    const o = raw as Record<string, unknown>;
    if (!Array.isArray(o.playerSpawn) || !Array.isArray(o.size)) return null;
    try {
      return levelToDoc(parseLevel(raw));
    } catch {
      return null;
    }
  },
};

export function makeAdapter(game: Game): LeveledAdapter {
  return {
    ...skitterSpec,
    schemaVersion: 2,
    title: 'SKITTERDOME',
    fileName: () => 'skitterdome-level.json',
    storageKey: () => LS_KEY,
    view: {
      element: game.renderer.domElement,
      pointerToCell(clientX, clientY) {
        game.updateNdc(clientX, clientY);
        return game.pointerCell();
      },
      pan: (dx, dy) => game.panEditor(dx, dy),
      zoom: (deltaY) => game.zoomEditor(deltaY),
      fit: () => game.fitEditorCamera(),
    },
    defaultLevel: () => levelToDoc(defaultLevelData()),
    onChange(doc) {
      game.level = docToLevel(doc);
      game.refreshLevel();
    },
    enterPlayMode(doc) {
      game.level = docToLevel(doc);
      game.setMode('play');
    },
  };
}
