/**
 * Stat-gated event eligibility (T007).
 *
 * Before T007, character stats (intelligence/creativity/social) were effectively
 * write-only — no v2 event read them in isEligible, so raising a stat opened no
 * doors. These events now READ a character stat in isEligible, turning the stat
 * trajectories built by Wave 1's performActivity into UNLOCKED content:
 *
 *   - career.flagshipProject            needs intelligence >= 60
 *   - random_creative_breakthrough      needs creativity   >= 60
 *   - random_networking_opportunity     needs social       >= 60
 *
 * Each test proves the gate FLIPS at the threshold: ineligible below, eligible
 * at/above. All three gate BONUS payoff content (not milestones), so a low stat
 * never blocks core progression.
 */
import { describe, it, expect } from 'vitest';

import {
  randomCatalog,
  CREATIVE_BREAKTHROUGH_CREATIVITY,
  NETWORKING_SOCIAL,
} from '../../src/events/v2/catalog/random.js';
import {
  careerCatalog,
  FLAGSHIP_PROJECT_INTELLIGENCE,
} from '../../src/events/v2/catalog/career.js';
import { isEventEligible } from '../../src/events/v2/engine/selector.js';
import type { EventDefinition, EventPlayerContext } from '../../src/events/v2/types.js';

function find(catalog: EventDefinition[], id: string): EventDefinition {
  const def = catalog.find((e) => e.id === id);
  expect(def, `event ${id} should exist`).toBeDefined();
  return def!;
}

function makePlayer(c: Record<string, unknown> = {}, overrides: Partial<EventPlayerContext> = {}): EventPlayerContext {
  return {
    userId: 'p1',
    c: { ageYears: 35, occupation: 'work', ...c },
    askedQuestions: new Set<string>(),
    eventLastFired: {},
    flags: new Set<string>(),
    r: [],
    ...overrides,
  };
}

describe('career.flagshipProject — intelligence gate', () => {
  const event = find(careerCatalog, 'flagshipProject');

  it('is INELIGIBLE just below the intelligence threshold', () => {
    const player = makePlayer({ intelligence: FLAGSHIP_PROJECT_INTELLIGENCE - 1 });
    expect(isEventEligible(event, player)).toBe(false);
  });

  it('is ELIGIBLE at the intelligence threshold', () => {
    const player = makePlayer({ intelligence: FLAGSHIP_PROJECT_INTELLIGENCE });
    expect(isEventEligible(event, player)).toBe(true);
  });

  it('is ELIGIBLE above the intelligence threshold', () => {
    const player = makePlayer({ intelligence: FLAGSHIP_PROJECT_INTELLIGENCE + 25 });
    expect(isEventEligible(event, player)).toBe(true);
  });

  it('still requires employment (smart but unemployed = ineligible)', () => {
    const player = makePlayer({ intelligence: 95, occupation: 'unemployed' });
    expect(isEventEligible(event, player)).toBe(false);
  });

  it('delivers an outsized money + prestige payoff (the studying reward)', () => {
    const lead = event.choices.find((ch) => ch.choiceId === 'lead_it')!;
    expect(lead.effects?.resources?.money ?? 0).toBeGreaterThan(0);
    expect(lead.effects?.stats?.prestige ?? 0).toBeGreaterThan(0);
  });
});

describe('random_creative_breakthrough — creativity gate', () => {
  const event = find(randomCatalog, 'random_creative_breakthrough');
  // dayOfYear must satisfy the cadence gate (dayOfYear % 40 === 13).
  const onCadence = 13;

  it('is INELIGIBLE just below the creativity threshold', () => {
    const player = makePlayer(
      { creativity: CREATIVE_BREAKTHROUGH_CREATIVITY - 1 },
      { dayOfYear: onCadence }
    );
    expect(isEventEligible(event, player, onCadence)).toBe(false);
  });

  it('is ELIGIBLE at the creativity threshold (on cadence)', () => {
    const player = makePlayer(
      { creativity: CREATIVE_BREAKTHROUGH_CREATIVITY },
      { dayOfYear: onCadence }
    );
    expect(isEventEligible(event, player, onCadence)).toBe(true);
  });

  it('stays INELIGIBLE off-cadence even with high creativity', () => {
    const offCadence = onCadence + 1;
    const player = makePlayer({ creativity: 90 }, { dayOfYear: offCadence });
    expect(isEventEligible(event, player, offCadence)).toBe(false);
  });

  it('produces real income (the monetized-creativity reward)', () => {
    expect(event.choices[0].effects?.resources?.money ?? 0).toBeGreaterThan(0);
  });
});

describe('random_networking_opportunity — social gate', () => {
  const event = find(randomCatalog, 'random_networking_opportunity');
  // dayOfYear must satisfy the cadence gate (dayOfYear % 42 === 17).
  const onCadence = 17;

  it('is INELIGIBLE just below the social threshold', () => {
    const player = makePlayer({ social: NETWORKING_SOCIAL - 1 }, { dayOfYear: onCadence });
    expect(isEventEligible(event, player, onCadence)).toBe(false);
  });

  it('is ELIGIBLE at the social threshold (on cadence)', () => {
    const player = makePlayer({ social: NETWORKING_SOCIAL }, { dayOfYear: onCadence });
    expect(isEventEligible(event, player, onCadence)).toBe(true);
  });

  it('stays INELIGIBLE off-cadence even with high social', () => {
    const offCadence = onCadence + 1;
    const player = makePlayer({ social: 95 }, { dayOfYear: offCadence });
    expect(isEventEligible(event, player, offCadence)).toBe(false);
  });
});
