import assert from 'node:assert/strict';
import { test } from 'node:test';

import {
  extractMonksTeleportEdges,
  filterScenesForImport,
  pickFoundryStartSceneId,
  planFoundrySceneGraph,
  sceneBackgroundSrc,
} from './foundryGraph';
import { decodeFoundryAssetPath } from './foundryPaths';
import type { FoundrySceneDoc } from './foundryTypes';
import { isSupportedFoundryPackage } from './foundryVersion';

function scene(id: string, name: string, extra: Partial<FoundrySceneDoc> = {}): FoundrySceneDoc {
  return { _id: id, name, navigation: true, ...extra };
}

function teleportTile(targetId: string) {
  return {
    flags: {
      'monks-active-tiles': {
        active: true,
        actions: [{ action: 'scene', data: { sceneid: { id: `Scene.${targetId}`, name: 'x' } } }],
      },
    },
  };
}

void test('filterScenesForImport keeps only navigation when present', () => {
  const scenes = [
    scene('aaaaaaaaaaaaaaaa', 'Nav', { navigation: true }),
    scene('bbbbbbbbbbbbbbbb', 'Hidden', { navigation: false }),
  ];
  assert.equal(filterScenesForImport(scenes).length, 1);
  assert.equal(filterScenesForImport(scenes)[0]?._id, 'aaaaaaaaaaaaaaaa');
});

void test('pickFoundryStartSceneId: min sort, then video, not name', () => {
  const scenes = [
    scene('aaaaaaaaaaaaaaaa', 'Тент', { sort: 0, tiles: [{}] }),
    scene('bbbbbbbbbbbbbbbb', 'Стартовая', {
      sort: 0,
      background: { src: 'modules/x/Map/Swamp_start.mp4' },
      tiles: [{}],
    }),
    scene('cccccccccccccccc', 'Болота', { sort: 100000 }),
  ];
  assert.equal(pickFoundryStartSceneId(scenes), 'bbbbbbbbbbbbbbbb');
});

void test('planFoundrySceneGraph: monks teleports create branches, not a line', () => {
  const hub = 'aaaaaaaaaaaaaaaa';
  const a = 'bbbbbbbbbbbbbbbb';
  const b = 'cccccccccccccccc';
  const start = 'dddddddddddddddd';
  const scenes = [
    scene(hub, 'Hub', {
      sort: 100000,
      tiles: [teleportTile(a), teleportTile(b)],
    }),
    scene(a, 'A', { sort: 200000, tiles: [teleportTile(hub)] }),
    scene(b, 'B', { sort: 300000, tiles: [teleportTile(hub)] }),
    scene(start, 'Intro', {
      sort: 0,
      background: { src: 'intro.mp4' },
      tiles: [teleportTile(hub)],
    }),
  ];
  const plan = planFoundrySceneGraph(scenes, [], []);
  assert.equal(plan.heuristic.kind, 'monks-teleports');
  assert.equal(plan.startSceneId, start);
  assert.ok(plan.edges.some((e) => e.sourceId === hub && e.targetId === a));
  assert.ok(plan.edges.some((e) => e.sourceId === hub && e.targetId === b));
  assert.ok(plan.edges.some((e) => e.sourceId === start && e.targetId === hub));
  // Не линейная цепочка из 3 рёбер подряд по всем сценам.
  assert.ok(plan.edges.length >= 3);
});

void test('extractMonksTeleportEdges ignores inactive tiles', () => {
  const scenes = [
    scene('aaaaaaaaaaaaaaaa', 'A', {
      tiles: [
        {
          flags: {
            'monks-active-tiles': {
              active: false,
              actions: [{ action: 'scene', data: { sceneid: 'Scene.bbbbbbbbbbbbbbbb' } }],
            },
          },
        },
      ],
    }),
    scene('bbbbbbbbbbbbbbbb', 'B'),
  ];
  assert.equal(extractMonksTeleportEdges(scenes).length, 0);
});

void test('planFoundrySceneGraph: sort-order fallback when no teleports', () => {
  const scenes = [
    scene('aaaaaaaaaaaaaaaa', 'Z', { sort: 3 }),
    scene('bbbbbbbbbbbbbbbb', 'A', { sort: 1 }),
    scene('cccccccccccccccc', 'M', { sort: 2 }),
  ];
  const plan = planFoundrySceneGraph(scenes, [], []);
  assert.equal(plan.heuristic.kind, 'navigation');
  assert.equal(plan.startSceneId, 'bbbbbbbbbbbbbbbb');
  assert.deepEqual(plan.orderedSceneIds[0], 'bbbbbbbbbbbbbbbb');
});

void test('sceneBackgroundSrc prefers background.src', () => {
  assert.equal(
    sceneBackgroundSrc({
      _id: 'aaaaaaaaaaaaaaaa',
      name: 'S',
      img: 'old.png',
      background: { src: 'new.webp' },
    }),
    'new.webp',
  );
});

void test('isSupportedFoundryPackage rejects pre-v11 maximum', () => {
  assert.equal(
    isSupportedFoundryPackage({ compatibility: { maximum: '10' }, coreVersion: '10.291' }).ok,
    false,
  );
  assert.equal(
    isSupportedFoundryPackage({ compatibility: { minimum: '11', verified: '12' }, coreVersion: '12.331' }).ok,
    true,
  );
});

void test('decodeFoundryAssetPath decodes %20', () => {
  assert.equal(
    decodeFoundryAssetPath('modules/x/Unwelcome_Spirits/Map/The%20Withered%20Grove%20(day).webp'),
    'modules/x/Unwelcome_Spirits/Map/The Withered Grove (day).webp',
  );
});
