import { describe, it, expect } from 'vitest';
import { buildCampaignContext, pickCreatureCandidates } from './context';
import { characterDefaults, type Campaign, type Character, type Encounter } from '@/lib/schemas';

function campaign(system: Campaign['system']): Campaign {
  return { id: 'c', name: 'Test', system, description: '', createdAt: '', updatedAt: '' };
}
function pc(name: string, level: number, system: Campaign['system']): Character {
  return {
    id: name, campaignId: 'c', system, kind: 'pc', name, ancestry: '', className: 'Fighter', level,
    abilities: { str: 14, dex: 12, con: 13, int: 10, wis: 11, cha: 9 },
    hp: { current: 20, max: 20, temp: 0 }, speed: 30, armorBonus: 0,
    skillRanks: {}, saveRanks: {}, perceptionRank: 'trained',
    ...characterDefaults(), notes: '', createdAt: '', updatedAt: '',
  };
}
function enc(combatants: { cr?: number; level?: number }[], over: Partial<Encounter> = {}): Encounter {
  return {
    id: 'e', campaignId: 'c', name: 'Fight', status: 'ended', round: 1, turnIndex: 0,
    combatants: combatants.map((c, i) => ({
      id: `m${i}`, name: 'Mob', kind: 'monster', initiative: 10, initBonus: 0, ac: 12,
      hp: { current: 5, max: 5, temp: 0 }, conditions: [], notes: '', ...c,
    })),
    log: [], createdAt: '2026-01-01', updatedAt: '2026-01-01', ...over,
  };
}

describe('buildCampaignContext', () => {
  it('states the right system constraint and forbids the other (pf2e)', () => {
    const ctx = buildCampaignContext({ campaign: campaign('pf2e'), characters: [pc('A', 3, 'pf2e')], encounters: [], quests: [], notes: [] });
    expect(ctx.systemLabel).toMatch(/pathfinder/i);
    expect(ctx.systemConstraint).toMatch(/pathfinder/i);
    expect(ctx.systemConstraint.toLowerCase()).toContain('never suggest content from any other game system');
    expect(ctx.partyLevels).toEqual([3]);
  });

  it('rates recent encounters using the party-level snapshot when present', () => {
    const snap = enc([{ cr: 1 }, { cr: 1 }], { partyLevelsSnapshot: [1, 1, 1, 1] });
    const ctx = buildCampaignContext({ campaign: campaign('5e'), characters: [pc('A', 10, '5e')], encounters: [snap], quests: [], notes: [] });
    expect(ctx.recentEncounters).toHaveLength(1);
    expect(ctx.recentEncounters[0]!.basedOnSnapshot).toBe(true);
    // Two CR-1 monsters vs four level-1 PCs is a real fight, not trivial.
    expect(ctx.recentEncounters[0]!.difficulty).not.toBe('trivial');
  });
});

describe('pickCreatureCandidates', () => {
  it('returns only level-appropriate 5e creatures, using cr', () => {
    const pool = [{ name: 'Rat', cr: 0, armor_class: 10, hit_points: 1 }, { name: 'Ogre', cr: 2 }, { name: 'Tarrasque', cr: 30 }];
    const got = pickCreatureCandidates('5e', [3, 3, 3, 3], pool, 'Medium');
    const names = got.map((c) => c.name);
    expect(names).toContain('Ogre');
    expect(names).not.toContain('Tarrasque');
    expect(got.find((c) => c.name === 'Rat')?.ac).toBe(10);
  });
  it('uses level (not cr) for pf2e', () => {
    const pool = [{ name: 'Goblin', level: 1, ac: 16, hp: 9 }, { name: 'Dragon', level: 18 }];
    const got = pickCreatureCandidates('pf2e', [2, 2, 2, 2], pool, 'Moderate');
    expect(got.map((c) => c.name)).toEqual(['Goblin']);
    expect(got[0]!.hp).toBe(9);
  });
});
