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

import { IncidentScheduler } from './IncidentScheduler.js';

function createMemorySave(state) {
  return {
    state: structuredClone(state),
    get() {
      return this.state;
    },
    set(partial) {
      const nextState = { ...this.state };
      for (const [key, value] of Object.entries(partial)) {
        if (value && typeof value === 'object' && !Array.isArray(value) && nextState[key] && typeof nextState[key] === 'object' && !Array.isArray(nextState[key])) {
          nextState[key] = { ...nextState[key], ...structuredClone(value) };
        } else {
          nextState[key] = structuredClone(value);
        }
      }
      this.state = nextState;
      return this.state;
    }
  };
}

function createScheduler({ phase = 'unease', quests = [] } = {}) {
  const sentMail = [];
  const save = createMemorySave({
    shift_started_at: '2026-04-25T11:00:00Z',
    world_flags: [],
    pressure: {},
    incidents: {}
  });

  const scheduler = new IncidentScheduler({
    loader: {
      pressureProfiles: new Map([
        ['kowalski_phase_2', {
          id: 'kowalski_phase_2',
          trigger_phase: 'unease',
          label: 'Dave Kowalski — Phase 2',
          escalation_steps: [
            {
              trigger_after_seconds: 0,
              notification: 'Phase pressure test message.',
              notification_severity: 'info',
              sender: 'Dave Kowalski <d.kowalski@axiomworks.internal>',
              subject: 'Phase pressure test'
            }
          ]
        }]
      ]),
      incidents: new Map(),
      get(type, id) {
        if (type === 'quests') {
          return {
            id,
            ticket_id: 'T099'
          };
        }

        return null;
      }
    },
    email: {
      send(payload) {
        sentMail.push(payload);
        return payload;
      }
    },
    quests: {
      getAllEntries() {
        return quests;
      }
    },
    save,
    phaseTracker: {
      getPhase() {
        return phase;
      }
    },
    tickets: {
      setPriority() {}
    },
    validator: {
      async evaluateRule() {
        return { passed: false, failures: ['not-applicable'] };
      }
    },
    now: () => new Date('2026-04-25T12:05:00Z').getTime(),
    tickSeconds: 30
  });

  return { scheduler, save, sentMail };
}

test('IncidentScheduler fires trigger_phase pressure profile when narrative phase matches', async () => {
  const { scheduler, save, sentMail } = createScheduler();

  await scheduler.tick();

  assert.equal(sentMail.length, 1);
  assert.equal(sentMail[0].from, 'Dave Kowalski <d.kowalski@axiomworks.internal>');
  assert.equal(sentMail[0].subject, 'Phase pressure test');
  assert.equal(sentMail[0].body, 'Phase pressure test message.');
  assert.deepEqual(save.get().pressure.kowalski_phase_2.fired_step_indexes, [0]);
});

test('IncidentScheduler does not fire trigger_phase pressure profile when narrative phase differs', async () => {
  const { scheduler, save, sentMail } = createScheduler({ phase: 'stability' });

  await scheduler.tick();

  assert.equal(sentMail.length, 0);
  assert.deepEqual(save.get().pressure, {});
});

test('IncidentScheduler trigger_phase pressure profile is independent of active quest pressure_profile fields', async () => {
  const { scheduler, save, sentMail } = createScheduler({
    quests: [[
      'Q099',
      { state: 'active', started_at: '2026-04-25T11:30:00Z' }
    ]]
  });

  await scheduler.tick();

  assert.equal(sentMail.length, 1);
  assert.equal(sentMail[0].subject, 'Phase pressure test');
  assert.deepEqual(save.get().pressure.kowalski_phase_2.fired_step_indexes, [0]);
  assert.equal(save.get().pressure.Q099, undefined);
});

test('IncidentScheduler handles missing pressureProfiles map without firing global pressure', async () => {
  const sentMail = [];
  const scheduler = new IncidentScheduler({
    loader: {
      incidents: new Map(),
      get() {
        return null;
      }
    },
    email: {
      send(payload) {
        sentMail.push(payload);
        return payload;
      }
    },
    quests: {
      getAllEntries() {
        return [];
      }
    },
    save: createMemorySave({
      shift_started_at: '2026-04-25T11:00:00Z',
      world_flags: [],
      pressure: {},
      incidents: {}
    }),
    phaseTracker: {
      getPhase() {
        return 'unease';
      }
    },
    tickets: {
      setPriority() {}
    },
    validator: {
      async evaluateRule() {
        return { passed: false, failures: ['not-applicable'] };
      }
    },
    now: () => new Date('2026-04-25T12:05:00Z').getTime(),
    tickSeconds: 30
  });

  await assert.doesNotReject(async () => scheduler.tick());
  assert.equal(sentMail.length, 0);
});

test('IncidentScheduler only fires a trigger_phase pressure step once', async () => {
  const { scheduler, save, sentMail } = createScheduler();

  await scheduler.tick();
  await scheduler.tick();

  assert.equal(sentMail.length, 1);
  assert.deepEqual(save.get().pressure.kowalski_phase_2.fired_step_indexes, [0]);
});
