/**
 * Daily-plan override tests
 *
 * Verifies that a player-set evening activity override (person.plannedActivity)
 * is honored by getDailyPlan / getRandomEveningActivity instead of the random
 * roll, that it is consumed after use, and that the field round-trips through
 * Person.toJSON() / the Person constructor (save/load).
 */
import { describe, it, expect } from 'vitest';
import { Person } from '../../src/models/Person';
import { Player } from '../../src/models/Player';
import { getDailyPlan, PLAYER_ACTIVITIES } from '../../src/game/engine/intradayActivity';

function makeWorker(plannedActivity?: string): Player {
  const character = new Person({
    id: 'char-1',
    firstname: 'Test',
    lastname: 'Worker',
    sex: 'Male',
    ageYears: 30,
    occupation: 'engineer', // adult, non-student, non-retired -> worker plan
    energy: 100,
    plannedActivity,
  });

  return new Player({
    userId: 'user-1',
    character,
    r: [],
    status: 'playing',
    date: '2024-06-12',
    dayOfWeek: 4, // Wednesday (weekday) -> deterministic weekday evening slot
    hourOfDay: 7,
    minuteOfHour: 0,
  });
}

describe('daily-plan override', () => {
  it('honors a set override for the evening slot instead of a random roll', () => {
    const player = makeWorker('study');
    getDailyPlan(player, player.c);

    const eveningSlot = player.c.dailyPlan.find((e: any) => e.time === 20) as any;
    expect(eveningSlot).toBeDefined();
    expect(eveningSlot.name).toBe(PLAYER_ACTIVITIES.study.name);
    expect(eveningSlot.title).toBe(PLAYER_ACTIVITIES.study.title);
  });

  it('consumes the override after generating the plan (one-shot)', () => {
    const player = makeWorker('hobby');
    getDailyPlan(player, player.c);
    expect(player.c.plannedActivity).toBeUndefined();

    // Regenerating the plan should now fall back to the random roll, not hobby.
    // (We assert only that the override was cleared, which is the contract;
    //  the random roll may legitimately land on any evening activity.)
  });

  it('falls back to a normal evening activity when no override is set', () => {
    const player = makeWorker(undefined);
    getDailyPlan(player, player.c);
    const eveningSlot = player.c.dailyPlan.find((e: any) => e.time === 20) as any;
    expect(eveningSlot).toBeDefined();
    expect(typeof eveningSlot.name).toBe('string');
    expect(eveningSlot.name.length).toBeGreaterThan(0);
  });

  it('drops an unknown override id without honoring it', () => {
    const player = makeWorker('totally-not-an-activity');
    getDailyPlan(player, player.c);
    expect(player.c.plannedActivity).toBeUndefined();
    const eveningSlot = player.c.dailyPlan.find((e: any) => e.time === 20) as any;
    // Falls back to a real evening activity name (not the bogus id).
    expect(eveningSlot.name).not.toBe('totally-not-an-activity');
  });

  it('round-trips plannedActivity through Person.toJSON() and back', () => {
    const character = new Person({
      id: 'char-1',
      firstname: 'Test',
      lastname: 'Worker',
      sex: 'Male',
      ageYears: 30,
      plannedActivity: 'exercise',
    });

    const json = character.toJSON();
    expect(json.plannedActivity).toBe('exercise');

    const restored = new Person(json);
    expect(restored.plannedActivity).toBe('exercise');
  });

  it('round-trips a queued override through full Player save/load', () => {
    const player = makeWorker('socialize');
    const json = player.toJSON() as any;
    const restored = new Player(json);
    expect(restored.c.plannedActivity).toBe('socialize');

    // And the restored player's plan honors the override.
    restored.dayOfWeek = 4;
    restored.hourOfDay = 7;
    getDailyPlan(restored, restored.c);
    const eveningSlot = restored.c.dailyPlan.find((e: any) => e.time === 20) as any;
    expect(eveningSlot.name).toBe(PLAYER_ACTIVITIES.socialize.name);
  });
});
