/**
 * Prestige-gated career tier tests (T011c).
 *
 * Verifies that the top tiers of prestige-gated occupations cannot be promoted
 * into below the prestige threshold, and CAN be once prestige is high enough.
 */
import { describe, it, expect, beforeEach } from 'vitest';
import { Person } from '../../../src/models/Person.js';
import { Player } from '../../../src/models/Player.js';
import {
  getOccupations,
  getOccupationByTitle,
  setJob,
  handleJob,
  getJobRecord,
  clearJobCaches,
  PRESTIGE_GATE_SENIOR,
  PRESTIGE_GATE_TOP,
  type JobRecord,
} from '../../../src/services/jobs/job_manager.js';

function makePlayer(prestige: number): Player {
  const character = new Person({
    id: 'char-1',
    firstname: 'Test',
    lastname: 'Player',
    ageYears: 30,
    education: 'doctorate_degree',
    prestige,
  });
  return new Player({
    userId: 'user-1',
    character,
    r: [],
    status: 'playing',
    date: '2024-06-15',
    hourOfDay: 10,
    minuteOfHour: 30,
  });
}

describe('Career prestige gating', () => {
  beforeEach(() => {
    clearJobCaches();
  });

  it('marks the top two tiers of prestige-gated occupations with minPrestige', () => {
    const swe = getOccupationByTitle('Software Engineer')!;
    const top = swe.levels[swe.levels.length - 1];
    const senior = swe.levels[swe.levels.length - 2];
    expect(top.minPrestige).toBe(PRESTIGE_GATE_TOP);
    expect(senior.minPrestige).toBe(PRESTIGE_GATE_SENIOR);
  });

  it('does not gate ordinary (non-prestige) occupations', () => {
    const janitor = getOccupationByTitle('Janitor')!;
    for (const level of janitor.levels) {
      expect(level.minPrestige ?? 0).toBe(0);
    }
  });

  it('blocks promotion into a prestige-gated tier below the threshold', () => {
    const player = makePlayer(0); // no prestige
    const lawyer = getOccupationByTitle('Lawyer')!;
    setJob(player.c, lawyer, player.date);

    const record = getJobRecord(player.c) as JobRecord;
    // Move to the second-from-top level so the NEXT promotion is gated (senior).
    record.level = lawyer.levels[lawyer.levels.length - 3];
    record.performance = 95; // promotion-eligible

    const result = handleJob(player, player.c);
    expect(result?.promoted).toBe(false);
    // Held at the ceiling, not promoted, not fired.
    expect(getJobRecord(player.c)!.performance).toBe(90);
    expect(getJobRecord(player.c)!.level.level).toBe(
      lawyer.levels[lawyer.levels.length - 3].level
    );
    // A gating message should have been queued.
    expect(player.messageQueue.some(m => /prestige/i.test(m))).toBe(true);
  });

  it('allows promotion into a prestige-gated tier at/above the threshold', () => {
    const player = makePlayer(PRESTIGE_GATE_SENIOR); // exactly the senior gate
    const lawyer = getOccupationByTitle('Lawyer')!;
    setJob(player.c, lawyer, player.date);

    const record = getJobRecord(player.c) as JobRecord;
    record.level = lawyer.levels[lawyer.levels.length - 3];
    record.performance = 95;

    const result = handleJob(player, player.c);
    expect(result?.promoted).toBe(true);
    expect(getJobRecord(player.c)!.level.level).toBe(
      lawyer.levels[lawyer.levels.length - 2].level
    );
  });

  it('still allows promotion into ungated tiers regardless of prestige', () => {
    const player = makePlayer(0);
    const swe = getOccupationByTitle('Software Engineer')!;
    setJob(player.c, swe, player.date);

    const record = getJobRecord(player.c) as JobRecord;
    record.level = swe.levels[0]; // entry -> 2nd level, ungated
    record.performance = 95;

    const result = handleJob(player, player.c);
    expect(result?.promoted).toBe(true);
    expect(getJobRecord(player.c)!.level.level).toBe(swe.levels[1].level);
  });
});
