/**
 * Database initialization for features and modules.
 *
 * - Features core : auth (et tout futur core ayant un db.js).
 * - Modules externes : découverts via discoverModules() ; chaque module
 *   exporte ses propres createTables/dropTables.
 *
 * Les permissions des modules (manifest.permissions) sont enregistrées AVANT
 * le seed de la BD pour qu'elles soient persistées et auto-attribuées au rôle
 * admin. register() n'est PAS appelé ici — les enregistrements runtime (pages,
 * nav, routes) ne sont pas nécessaires pour l'init BD et tireraient des imports
 * Next.js incompatibles avec le contexte CLI.
 */

import { createTables as authCreate, dropTables as authDrop } from './auth/db.js';
import { createTables as mediaCreate, dropTables as mediaDrop } from './media/schema.server.js';
import { done, fail, info, step } from '@zen/core/shared/logger';
import { loadModulesForCli, validateModuleEnvVars } from '../core/modules/discover.server.js';
import { getRegisteredModules } from '../core/modules/registry.js';
import { registerPermissions } from '../core/users/permissions-registry.js';

// Auth en premier (les autres features peuvent référencer zen_auth_users via FK).
// Les permissions des features additionnelles sont enregistrées au module-load
// dans leur schema.server.js, ce qui garantit qu'elles sont dans le registre
// avant le seed des rôles dans auth.createTables.
const CORE_FEATURES = [
  { name: 'auth',  createTables: authCreate,  dropTables: authDrop  },
  { name: 'media', createTables: mediaCreate, dropTables: mediaDrop },
];

async function loadModules() {
  await loadModulesForCli();
  const modules = getRegisteredModules();
  validateModuleEnvVars(modules);

  // Enregistre les permissions déclarées dans le manifest de chaque module.
  // register() n'est PAS appelé ici : les enregistrements runtime (pages, nav,
  // routes, storage) ne servent à rien dans le contexte CLI et tireraient des
  // imports Next.js (next/headers, JSX) qui ne sont pas disponibles en Node.js.
  for (const mod of modules) {
    if (Array.isArray(mod.manifest?.permissions)) {
      registerPermissions(mod.manifest.permissions);
    }
  }
  return modules;
}

export async function initFeatures() {
  const created = [];
  const skipped = [];

  step('Initializing feature databases...');

  // Charger les modules d'abord pour que leurs permissions soient connues
  // au moment du seed (et donc auto-attribuées au rôle admin).
  const modules = await loadModules();

  const targets = [
    ...CORE_FEATURES,
    ...modules
      .filter(m => typeof m.createTables === 'function')
      .map(m => ({ name: m.manifest.name, createTables: m.createTables, dropTables: m.dropTables })),
  ];

  for (const { name, createTables } of targets) {
    try {
      step(`Initializing ${name}...`);
      if (typeof createTables !== 'function') {
        info(`${name} has no createTables function`);
        continue;
      }
      const result = await createTables();
      if (result?.created) created.push(...result.created);
      if (result?.skipped) skipped.push(...result.skipped);
      done(`${name} initialized`);
    } catch (error) {
      fail(`${name}: ${error.message}`);
      throw error;
    }
  }

  return { created, skipped };
}

export async function dropFeatures() {
  const modules = await loadModules();

  // Ordre de création : core, puis modules. Drop = ordre inverse pour que
  // les tables modules (qui peuvent avoir des FK vers core) tombent d'abord.
  const targets = [
    ...CORE_FEATURES,
    ...modules
      .filter(m => typeof m.dropTables === 'function')
      .map(m => ({ name: m.manifest.name, dropTables: m.dropTables })),
  ];

  for (const { name, dropTables } of [...targets].reverse()) {
    try {
      if (typeof dropTables !== 'function') {
        info(`${name} has no dropTables function`);
        continue;
      }
      await dropTables();
    } catch (error) {
      fail(`${name}: ${error.message}`);
      throw error;
    }
  }
}
