// server/tests/handlers/hangout.test.ts
import { describe, it, expect } from 'vitest';
import { handleHangOut } from '../../src/handlers/friendship.js';
import { Player } from '../../src/models/Player.js';
import { Person } from '../../src/models/Person.js';

function makeSession() {
  const character = new Person({ firstname: 'Hero', sex: 'female' } as any);
  character.ageDays = 7300;
  character.ageYears = 20;
  character.energy = 80;
  character.happiness = 50;
  const player = new Player({ userId: 'hangout-test', character } as any);
  const friend = new Person({ firstname: 'Ana', sex: 'female' } as any);
  friend.id = 'friend-1';
  friend.status = 'alive';
  friend.relationships = ['friend'];
  friend.affinity = 50;
  player.r = [friend];

  const sent: any[] = [];
  const session = {
    player,
    sent,
    send(msg: unknown) {
      sent.push(msg);
    },
    sendPlayerObject() {
      sent.push({ type: 'playerObject' });
    },
    async savePlayer() {},
  };
  return { session: session as any, player, friend, sent };
}

describe('handleHangOut', () => {
  it('costs energy, raises affinity, stamps interaction days, acks', async () => {
    const { session, player, friend, sent } = makeSession();
    await handleHangOut({ personId: 'friend-1' }, session);

    expect(player.c.energy).toBe(65);
    expect(friend.affinity).toBe(56);
    expect(player.c.happiness).toBe(53);
    expect(friend.lastFriendInteractionDay).toBe(7300);
    expect(friend.lastHangOutDay).toBe(7300);

    const ack = sent.find((m) => m.type === 'hangOutResult');
    expect(ack).toMatchObject({ success: true, personId: 'friend-1', affinity: 56 });
    expect(sent.some((m) => m.type === 'playerObject')).toBe(true);
  });

  it('rejects an unknown person', async () => {
    const { session, sent } = makeSession();
    await handleHangOut({ personId: 'nobody' }, session);
    expect(sent[0]).toMatchObject({ type: 'error' });
  });

  it('rejects a non-friend NPC', async () => {
    const { session, friend, sent } = makeSession();
    friend.relationships = ['coworker'];
    await handleHangOut({ personId: 'friend-1' }, session);
    expect(sent[0]).toMatchObject({ type: 'error' });
  });

  it('rejects when too tired (energy < 15)', async () => {
    const { session, player, sent } = makeSession();
    player.c.energy = 10;
    await handleHangOut({ personId: 'friend-1' }, session);
    expect(sent[0]).toMatchObject({ type: 'error' });
  });

  it('rejects below the min-affinity gate (mirrors the iOS >= 30 gate)', async () => {
    const { session, friend, sent } = makeSession();
    friend.affinity = 29;
    await handleHangOut({ personId: 'friend-1' }, session);
    expect(sent[0]).toMatchObject({ type: 'error' });
    expect(friend.affinity).toBe(29);
  });

  it('allows hanging out exactly at the min-affinity threshold', async () => {
    const { session, friend, sent } = makeSession();
    friend.affinity = 30;
    await handleHangOut({ personId: 'friend-1' }, session);
    expect(sent.find((m) => m.type === 'hangOutResult')).toMatchObject({ success: true });
    expect(friend.affinity).toBe(36);
  });

  it('enforces the 3-day per-NPC cooldown', async () => {
    const { session, player, friend, sent } = makeSession();
    friend.lastHangOutDay = player.c.ageDays - 1;
    await handleHangOut({ personId: 'friend-1' }, session);
    expect(sent[0]).toMatchObject({ type: 'error' });
    expect(friend.affinity).toBe(50);
  });
});
