import { NPC_ROLLTABLE_DEFINITIONS } from './data/npcTables.js';

const MODULE_ID = 'mgt2-compendium-amiral-denisov';
const PACK_ID = `${MODULE_ID}.tables-pnj`;
const WORLD_FOLDER_NAME = 'MgT2e — Tables PNJ';
const ROLLTABLES_VERSION = 1;

function entryText(entry) {
  if (typeof entry.d66 === 'number') return `[${entry.d66}] ${entry.text}`;
  if (typeof entry.roll === 'number') return `[${entry.roll}] ${entry.text}`;
  return entry.text;
}

function buildTableResults(entries) {
  return entries.map((entry, index) => ({
    type: CONST.TABLE_RESULT_TYPES.TEXT,
    text: entryText(entry),
    weight: 1,
    range: [index + 1, index + 1],
    drawn: false,
  }));
}

function buildTableData(definition, extra = {}) {
  return {
    name: definition.name,
    description: 'Table synchronisée automatiquement depuis les règles PNJ du module.',
    formula: definition.formula,
    replacement: true,
    displayRoll: true,
    results: buildTableResults(definition.entries),
    flags: {
      [MODULE_ID]: {
        tableKey: definition.key,
        syncVersion: ROLLTABLES_VERSION,
      },
    },
    ...extra,
  };
}

function normalizeResults(results) {
  return results.map((result) => ({
    type: result.type,
    text: result.name ?? result.description ?? result.text ?? '',
    weight: result.weight,
    range: Array.from(result.range),
  }));
}

function needsSync(existing, wanted) {
  if (!existing) return true;
  if (existing.name !== wanted.name) return true;
  if (existing.formula !== wanted.formula) return true;
  if (existing.replacement !== wanted.replacement) return true;
  const currentVersion = existing.getFlag(MODULE_ID, 'syncVersion');
  if (currentVersion !== ROLLTABLES_VERSION) return true;
  return JSON.stringify(normalizeResults(existing.results.contents)) !== JSON.stringify(normalizeResults(wanted.results));
}

function getExistingKey(document) {
  return document.getFlag(MODULE_ID, 'tableKey') ?? document.name;
}

async function syncCompendiumPack() {
  const pack = game.packs.get(PACK_ID);
  if (!pack) throw new Error(`Pack introuvable : ${PACK_ID}`);

  await pack.getIndex();
  const existingDocs = await pack.getDocuments();
  const existingByKey = new Map(existingDocs.map((doc) => [getExistingKey(doc), doc]));
  const toCreate = [];
  const toUpdate = [];
  const wasLocked = pack.locked;

  try {
    if (wasLocked && typeof pack.configure === 'function') await pack.configure({ locked: false });

    for (const definition of NPC_ROLLTABLE_DEFINITIONS) {
      const wanted = buildTableData(definition);
      const existing = existingByKey.get(definition.key);
      if (!existing) {
        toCreate.push(wanted);
        continue;
      }
      if (needsSync(existing, wanted)) {
        toUpdate.push({
          _id: existing.id,
          ...wanted,
        });
      }
    }

    if (toCreate.length) await RollTable.createDocuments(toCreate, { pack: pack.collection });
    if (toUpdate.length) await RollTable.updateDocuments(toUpdate, { pack: pack.collection });
  } finally {
    if (wasLocked && typeof pack.configure === 'function') await pack.configure({ locked: true });
  }
}

async function getWorldFolder() {
  let folder = game.folders.find((entry) => entry.type === 'RollTable' && entry.name === WORLD_FOLDER_NAME);
  if (folder) return folder;
  return Folder.create({
    name: WORLD_FOLDER_NAME,
    type: 'RollTable',
    color: '#c9a227',
  });
}

async function syncWorldFallback() {
  const folder = await getWorldFolder();
  const existingDocs = game.tables.filter((doc) => doc.folder?.id === folder.id);
  const existingByKey = new Map(existingDocs.map((doc) => [getExistingKey(doc), doc]));
  const toCreate = [];
  const toUpdate = [];

  for (const definition of NPC_ROLLTABLE_DEFINITIONS) {
    const wanted = buildTableData(definition, { folder: folder.id });
    const existing = existingByKey.get(definition.key);
    if (!existing) {
      toCreate.push(wanted);
      continue;
    }
    if (needsSync(existing, wanted)) {
      toUpdate.push({
        _id: existing.id,
        ...wanted,
      });
    }
  }

  if (toCreate.length) await RollTable.createDocuments(toCreate);
  if (toUpdate.length) await RollTable.updateDocuments(toUpdate);
}

export async function syncNpcRollTables() {
  if (!game.user?.isGM) return;

  try {
    await syncCompendiumPack();
  } catch (error) {
    console.error(`${MODULE_ID} | Échec de synchronisation du pack RollTable`, error);
    await syncWorldFallback();
    ui.notifications.warn('Tables PNJ synchronisées dans le monde courant (fallback) — le pack de compendium n’a pas pu être mis à jour.');
  }
}
