// scripts/test-coach-join-gate.mjs — ECO-39 verification.
//
// Asserts that the daily lesson loop is GATED on the coach having joined
// the WhatsApp group:
//   1. New Hotmart-approved mentee → coachJoinedAt is null
//   2. tickSilverUser(slot=8) → skipped 'awaiting-coach-join' (no lesson)
//   3. applyCoachJoin → state flips, copy sent to group
//   4. tickSilverUser(slot=8) → fires the lesson (no longer skipped)
//   5. Admin force-coach-join endpoint also works
//   6. Idempotency: a second coach-join call is a no-op
//
//   node scripts/test-coach-join-gate.mjs

import { mkdirSync, rmSync, existsSync, cpSync, readFileSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import { tmpdir } from 'os';
import { configureTest, _resetTestState, readOutbox, clearOutbox } from '../lib/whatsappAdapter.js';
import { handleHotmartWebhook } from '../lib/hotmartWebhook.js';
import { tickSilverUser, applyCoachJoin } from '../lib/silverCourse.js';
import { loadSilver } from '../lib/silverStore.js';
import { handleCoachAdminRequest } from '../lib/coachAdmin.js';

const REAL = dirname(fileURLToPath(import.meta.url)).replace(/\/scripts$/, '');
const TMP = join(tmpdir(), `ecobot-coach-join-${Date.now()}`);

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 : ''}`); }
}

async function main() {
  if (existsSync(TMP)) rmSync(TMP, { recursive: true, force: true });
  mkdirSync(TMP, { recursive: true });
  cpSync(join(REAL, 'data'), join(TMP, 'data'), { recursive: true });
  configureTest();
  _resetTestState();
  process.env.HOTMART_HOTTOK = 'TEST_HOTTOK';
  process.env.WHATSAPP_ORCHESTRATOR_TOKEN = 'TEST_ORCH_TOKEN';

  // 1. Hotmart onboarding
  const fixture = JSON.parse(readFileSync(join(REAL, 'scripts', 'fixtures', 'hotmart-approved.json'), 'utf8'));
  fixture.hottok = 'TEST_HOTTOK';
  const r = await handleHotmartWebhook(TMP, {
    rawBody: Buffer.from(JSON.stringify(fixture)),
    headers: { 'content-type': 'application/json' },
  });
  check('hotmart approved', r.status === 200);
  const slug = r.body.slug;

  let state = loadSilver(TMP, slug);
  check('coachJoinedAt is null after onboarding', state.coachJoinedAt === null);

  // Pretend the user is already past their start date (initSilver sets startedAt = now,
  // but the morningSend "before-start-date" guard would otherwise also fire). Force
  // startedAt to be 1h in the past.
  state.startedAt = new Date(Date.now() - 3600_000).toISOString();
  // Also pre-seed an awaiting lesson for the nudge slots (14:00/18:00) test.
  // We'll set this AFTER the gate flips below.
  (await import('../lib/silverStore.js')).saveSilver(TMP, slug, state);

  // 2. tick at 08:00 → skipped 'awaiting-coach-join'
  clearOutbox();
  let tick = await tickSilverUser(TMP, slug, 8);
  check('08:00 tick skipped before coach joins', tick.skipped === 'awaiting-coach-join', `got ${JSON.stringify(tick)}`);
  let outbox = readOutbox().filter(m => m.text);
  check('no message sent at 08:00 before coach joins', outbox.length === 0);

  // 3. applyCoachJoin
  clearOutbox();
  const join1 = await applyCoachJoin(TMP, slug, {
    coachJid: '49170000000@s.whatsapp.net',
    coachName: 'Marco',
    source: 'baileys-event',
  });
  check('applyCoachJoin returned ok', join1.ok === true);
  state = loadSilver(TMP, slug);
  check('coachJoinedAt now set', !!state.coachJoinedAt);
  check('coachJid persisted', state.coachJid === '49170000000@s.whatsapp.net');
  check('coachName persisted', state.coachName === 'Marco');
  check('coachJoinSource = baileys-event', state.coachJoinSource === 'baileys-event');

  outbox = readOutbox().filter(m => m.text);
  check('coach-join message sent', outbox.some(m => /Welcome Marco|Welcome marco|all set/i.test(m.text)));

  // 4. tick at 08:00 → no longer skipped (sends a lesson)
  clearOutbox();
  tick = await tickSilverUser(TMP, slug, 8);
  check('08:00 tick AFTER coach joins is NOT skipped on awaiting-coach-join',
        tick.skipped !== 'awaiting-coach-join', `got ${JSON.stringify(tick)}`);
  // It should send the L01 lesson (or skip on already-sent-today, but the lesson is fresh)
  check('a lesson was sent', !!tick.sent || tick.skipped === 'before-start-date',
        `got ${JSON.stringify(tick)}`);

  // 5. Idempotency: second join call is a no-op
  clearOutbox();
  const join2 = await applyCoachJoin(TMP, slug, {
    coachJid: '49170000001@s.whatsapp.net',
    coachName: 'Different Coach',
    source: 'force-admin',
  });
  check('second join returns ok with skipped flag', join2.ok === true && join2.skipped === 'already-joined');
  state = loadSilver(TMP, slug);
  check('coachJid unchanged on idempotent call', state.coachJid === '49170000000@s.whatsapp.net');
  outbox = readOutbox().filter(m => m.text);
  check('no second coach-join message sent', outbox.length === 0);

  // 6. Admin force-coach-join endpoint (on a fresh mentee)
  // Reset the existing state to test the endpoint
  state.coachJoinedAt = null;
  state.coachJid = null;
  state.coachName = null;
  state.coachJoinSource = null;
  (await import('../lib/silverStore.js')).saveSilver(TMP, slug, state);

  clearOutbox();
  const adminReq = {
    method: 'POST',
    url: `/admin/silver/users/${slug}/force-coach-join`,
    headers: { authorization: 'Bearer TEST_ORCH_TOKEN' },
  };
  const adminResult = await handleCoachAdminRequest(TMP, adminReq, Buffer.from(JSON.stringify({
    coachEmail: 'marco.disalvo999@gmail.com',
    coachJid: '49170000099@s.whatsapp.net',
    coachName: 'Marco D.',
  })));
  check('admin force-coach-join returns 200', adminResult.status === 200);
  state = loadSilver(TMP, slug);
  check('admin force flipped coachJoinedAt', !!state.coachJoinedAt);
  check('admin force set source=force-admin', state.coachJoinSource === 'force-admin');

  // 7. Bad-token rejection on the new endpoint
  const badReq = {
    method: 'POST',
    url: `/admin/silver/users/${slug}/force-coach-join`,
    headers: { authorization: 'Bearer WRONG' },
  };
  const badResult = await handleCoachAdminRequest(TMP, badReq, Buffer.from('{}'));
  check('bad token → 401 on force-coach-join', badResult.status === 401);

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

main().catch(e => { console.error(e); process.exit(1); });
