// scripts/test-module-gate.mjs — generalized module-completion gate.
//
// Refined flow: a module is complete when (a) all lessons in that module
// have completedAt AND (b) all gating tasks (week === N or gatesModule === N)
// have status='claimed'. Asserts:
//   1. Lessons-only → not ready, tasksRemaining lists all module tasks
//   2. Lessons + tasks → ready=true, modulesCompleted[N]=true,
//      module<N>CompletedAt set
//   3. Module 1 also flips accessLevel → dossier_pending
//   4. Calling again on a complete module is idempotent
//   5. Different module isolation (M2 doesn't flip when only M1 is done)
//   6. Modules 2-4 work the same way (no accessLevel side-effect)
//
//   node scripts/test-module-gate.mjs

import { fileURLToPath } from 'url';
import { dirname } from 'path';
import {
  defaultSilverState, loadCatalog, loadTaskRegistry,
  maybeMarkModuleComplete, ACCESS_LEVELS,
} from '../lib/silverStore.js';

const SCRIPT_DIR = dirname(dirname(fileURLToPath(import.meta.url))).replace(/\/scripts$/, '');

let pass = 0, fail = 0;
function check(label, ok, detail) {
  if (ok) { pass += 1; console.log(`✅ ${label}`); }
  else    { fail += 1; console.log(`❌ ${label}${detail ? ' — ' + detail : ''}`); }
}

function freshState() {
  const s = defaultSilverState();
  s.slug = 'test';
  s.startedAt = new Date().toISOString();
  return s;
}

function completeAllLessonsForModule(state, scriptDir, moduleN) {
  const cat = loadCatalog(scriptDir);
  for (const l of cat.lessons.filter(l => l.module === moduleN)) {
    state.lessons[l.id] = { completedAt: new Date().toISOString() };
  }
}

function claimAllTasksForModule(state, scriptDir, moduleN) {
  const reg = loadTaskRegistry(scriptDir);
  for (const t of reg.tasks.filter(t => (typeof t.gatesModule === 'number' ? t.gatesModule : t.week) === moduleN)) {
    state.tasks[t.id] = { taskId: t.id, status: 'claimed' };
  }
}

function main() {
  // 1. Empty state — neither lessons nor tasks done
  let s = freshState();
  let r = maybeMarkModuleComplete(SCRIPT_DIR, s, 1);
  check('empty state: ready=false', r.ready === false);
  check('empty state: lessonsRemaining > 0', r.lessonsRemaining.length > 0);
  check('empty state: tasksRemaining > 0', r.tasksRemaining.length > 0);

  // 2. Lessons done, tasks not → ready=false, tasksRemaining still populated
  completeAllLessonsForModule(s, SCRIPT_DIR, 1);
  r = maybeMarkModuleComplete(SCRIPT_DIR, s, 1);
  check('lessons-only: ready=false', r.ready === false);
  check('lessons-only: lessonsDone=true', r.lessonsDone === true);
  check('lessons-only: tasksRemaining=4', r.tasksRemaining.length === 4);
  check('lessons-only: modulesCompleted[1]=false', !s.modulesCompleted[1]);

  // 3. Claim all module-1 tasks → ready=true, state mutates
  claimAllTasksForModule(s, SCRIPT_DIR, 1);
  r = maybeMarkModuleComplete(SCRIPT_DIR, s, 1);
  check('lessons + tasks: ready=true', r.ready === true);
  check('lessons + tasks: tasksRemaining=0', r.tasksRemaining.length === 0);
  check('state.modulesCompleted[1]=true', s.modulesCompleted[1] === true);
  check('state.module1CompletedAt set', !!s.module1CompletedAt);
  check('M1 flips accessLevel → dossier_pending', s.accessLevel === ACCESS_LEVELS.DOSSIER_PENDING);

  // 4. Idempotency — second call doesn't re-mutate
  const beforeTs = s.module1CompletedAt;
  r = maybeMarkModuleComplete(SCRIPT_DIR, s, 1);
  check('second call: ready=true (still)', r.ready === true);
  check('idempotent: timestamp unchanged', s.module1CompletedAt === beforeTs);

  // 5. M2 not flipped when only M1 lessons done
  s = freshState();
  completeAllLessonsForModule(s, SCRIPT_DIR, 1);
  claimAllTasksForModule(s, SCRIPT_DIR, 1);
  maybeMarkModuleComplete(SCRIPT_DIR, s, 1);
  const r2 = maybeMarkModuleComplete(SCRIPT_DIR, s, 2);
  check('M1 done but M2 not: ready=false', r2.ready === false);
  check('M2 modulesCompleted[2]=false', !s.modulesCompleted[2]);

  // 6. Module 2 works the same way (no accessLevel side effect)
  s = freshState();
  completeAllLessonsForModule(s, SCRIPT_DIR, 2);
  claimAllTasksForModule(s, SCRIPT_DIR, 2);
  const r3 = maybeMarkModuleComplete(SCRIPT_DIR, s, 2);
  check('M2 lessons + tasks: ready=true', r3.ready === true);
  check('state.modulesCompleted[2]=true', s.modulesCompleted[2] === true);
  check('state.module2CompletedAt set', !!s.module2CompletedAt);
  check('M2 does NOT flip accessLevel', s.accessLevel === ACCESS_LEVELS.COURSE_ONLY);

  // 7. Module 4 (final) works
  s = freshState();
  completeAllLessonsForModule(s, SCRIPT_DIR, 4);
  claimAllTasksForModule(s, SCRIPT_DIR, 4);
  const r4 = maybeMarkModuleComplete(SCRIPT_DIR, s, 4);
  check('M4 lessons + tasks: ready=true', r4.ready === true);
  check('state.modulesCompleted[4]=true', s.modulesCompleted[4] === true);

  console.log(`\n${pass} passed, ${fail} failed`);
  process.exit(fail === 0 ? 0 : 1);
}

main();
