/**
 * Task 0-A: the ONLINE economy was frozen. PlayerSession.processWeekTick only
 * called savePlayer(), so online players never earned salary or paid expenses.
 * It now invokes the shared `applyWeeklyFinances` for the player character, so
 * an online week tick changes `person.money`.
 *
 * Also asserts the online weekly money delta == the offline GameEngine delta for
 * the same fixture (both go through the same shared function).
 */
import { describe, it, expect, vi } from 'vitest';

import { Person } from '../../src/models/Person.js';
import { Player } from '../../src/models/Player.js';
import { PlayerSession } from '../../src/game/PlayerSession.js';
import { applyWeeklyFinances } from '../../src/game/finance.js';

class MockWebSocket {
  messages: string[] = [];
  readyState = 1; // OPEN
  send(data: string) { this.messages.push(data); }
  close() { this.readyState = 3; }
}

function makeWorkingPlayer(money: number, salary: number): Player {
  const character = new Person({
    id: 'char-1',
    firstname: 'Test',
    lastname: 'Worker',
    sex: 'Male',
    ageYears: 30,
    occupation: 'engineer',
    salary,
    money,
  } as never);
  return new Player({
    userId: 'week-tick-player',
    character,
    status: 'playing',
    date: '2024-06-15',
  });
}

function callWeekTick(session: PlayerSession): void {
  (session as unknown as { processWeekTick: () => void }).processWeekTick();
}

describe('PlayerSession.processWeekTick — online economy unfrozen (Fix 0-A)', () => {
  it('changes player money on a week tick (was previously frozen)', () => {
    const player = makeWorkingPlayer(100, 2000);
    const ws = new MockWebSocket();
    // Don't actually hit the DB during the save call.
    const session = new PlayerSession(ws as unknown as never, player);
    vi.spyOn(session as unknown as { savePlayer: () => Promise<void> }, 'savePlayer')
      .mockResolvedValue(undefined);

    const before = player.c.money;
    callWeekTick(session);
    const after = player.c.money;

    // New economy: gross 500, scaling rent 150 (clamp(500*0.30,50,1250)),
    // surplus 350, normal savings 0.35 (raised for meaningful wealth) -> net +122.5.
    expect(after).not.toBe(before);
    expect(after).toBeCloseTo(100 + 122.5, 5);
  });

  it('online weekly delta equals offline (shared applyWeeklyFinances) delta', () => {
    // Online path: run a real week tick.
    const onlinePlayer = makeWorkingPlayer(100, 2000);
    const ws = new MockWebSocket();
    const session = new PlayerSession(ws as unknown as never, onlinePlayer);
    vi.spyOn(session as unknown as { savePlayer: () => Promise<void> }, 'savePlayer')
      .mockResolvedValue(undefined);

    const onlineBefore = onlinePlayer.c.money;
    callWeekTick(session);
    const onlineDelta = onlinePlayer.c.money - onlineBefore;

    // Offline path proxy: the exact same shared function the GameEngine uses.
    const offlinePerson = new Person({
      id: 'char-1',
      firstname: 'Test',
      lastname: 'Worker',
      sex: 'Male',
      ageYears: 30,
      occupation: 'engineer',
      salary: 2000,
      money: 100,
    } as never);
    const offlineBefore = offlinePerson.money;
    applyWeeklyFinances(offlinePerson);
    const offlineDelta = offlinePerson.money - offlineBefore;

    expect(onlineDelta).toBe(offlineDelta);
  });
});
