/**
 * Affinity-gated event eligibility (T008).
 *
 * Two catalog events now READ NPC affinity in their isEligible:
 *   - random_close_friend_invite: needs a relation with affinity >= 65
 *   - health.crisisSupportFromLovedOne: needs a prior medical emergency AND a
 *     living relation with affinity >= 60
 *
 * These verify the gate: ineligible below threshold, eligible above.
 */
import { describe, it, expect } from 'vitest';

import { randomCatalog, CLOSE_FRIEND_AFFINITY } from '../../src/events/v2/catalog/random.js';
import { healthCatalog } from '../../src/events/v2/catalog/health.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(overrides: Partial<EventPlayerContext> = {}): EventPlayerContext {
  return {
    userId: 'p1',
    c: { ageYears: 30 },
    askedQuestions: new Set<string>(),
    eventLastFired: {},
    flags: new Set<string>(),
    dayOfYear: 50, // multiple of 50, passes the close-friend cadence gate
    r: [],
    ...overrides,
  };
}

describe('random_close_friend_invite — affinity gate', () => {
  const event = find(randomCatalog, 'random_close_friend_invite');

  it('is INELIGIBLE when no relation is close enough', () => {
    const player = makePlayer({
      r: [{ id: 'a', firstname: 'Acquaintance', affinity: CLOSE_FRIEND_AFFINITY - 1, status: 'alive' }],
    });
    expect(isEventEligible(event, player, 50)).toBe(false);
  });

  it('is ELIGIBLE when a relation likes the player at/above the threshold', () => {
    const player = makePlayer({
      r: [{ id: 'b', firstname: 'Bestie', affinity: CLOSE_FRIEND_AFFINITY + 5, status: 'alive' }],
    });
    expect(isEventEligible(event, player, 50)).toBe(true);
  });

  it('ignores a deceased close friend', () => {
    const player = makePlayer({
      r: [{ id: 'c', firstname: 'Lost', affinity: 100, status: 'dead' }],
    });
    expect(isEventEligible(event, player, 50)).toBe(false);
  });
});

describe('health.crisisSupportFromLovedOne — affinity gate', () => {
  const event = find(healthCatalog, 'health.crisisSupportFromLovedOne');

  it('is INELIGIBLE without a prior medical emergency', () => {
    const player = makePlayer({
      askedQuestions: new Set<string>(),
      r: [{ id: 'm', firstname: 'Mom', affinity: 90, status: 'alive' }],
    });
    expect(isEventEligible(event, player)).toBe(false);
  });

  it('is INELIGIBLE when the player has only low-affinity relations', () => {
    const player = makePlayer({
      askedQuestions: new Set<string>(['health.medicalEmergency']),
      r: [{ id: 'm', firstname: 'Mom', affinity: 40, status: 'alive' }],
    });
    expect(isEventEligible(event, player)).toBe(false);
  });

  it('is ELIGIBLE after an emergency when a high-affinity relation exists', () => {
    const player = makePlayer({
      askedQuestions: new Set<string>(['health.medicalEmergency']),
      r: [{ id: 'm', firstname: 'Mom', affinity: 75, status: 'alive' }],
    });
    expect(isEventEligible(event, player)).toBe(true);
  });

  it('provides real money + mood relief in its effects', () => {
    const choice = event.choices[0];
    expect(choice.effects?.resources?.money).toBeGreaterThan(0);
    expect((choice.effects?.stats?.happiness ?? 0)).toBeGreaterThan(0);
  });
});
