import { describe, it, expect } from 'vitest';
import { deriveState } from './creatureState';
import { concentrationDC } from './cast';
import type { Condition } from '@/lib/schemas/common';

const cond = (name: string, value?: number): Condition => (value !== undefined ? { name, value } : { name });

describe('deriveState (5e)', () => {
  it('grappled zeroes speed', () => {
    const s = deriveState('5e', 30, [cond('Grappled')]);
    expect(s.speed).toBe(0);
    expect(s.badges).toContain('Speed 0');
  });

  it('poisoned imposes disadvantage on attacks and ability checks', () => {
    const s = deriveState('5e', 30, [cond('Poisoned')]);
    expect(s.attackModifier).toBe('disadvantage');
    expect(s.abilityCheckDisadvantage).toBe(true);
  });

  it('restrained: speed 0, disadv attacks, attacked with advantage, dex save disadvantage', () => {
    const s = deriveState('5e', 30, [cond('Restrained')]);
    expect(s.speed).toBe(0);
    expect(s.attackModifier).toBe('disadvantage');
    expect(s.attacksAgainstModifier).toBe('advantage');
    expect(s.saveModifiers.dex).toBe('disadvantage');
  });

  it('paralyzed auto-fails str/dex saves and incapacitates', () => {
    const s = deriveState('5e', 30, [cond('Paralyzed')]);
    expect(s.incapacitated).toBe(true);
    expect(s.saveModifiers.str).toBe('auto-fail');
    expect(s.saveModifiers.dex).toBe('auto-fail');
  });

  it('opposing advantage and disadvantage cancel to normal', () => {
    // invisible grants advantage to attack; poisoned imposes disadvantage → normal
    const s = deriveState('5e', 30, [cond('Invisible'), cond('Poisoned')]);
    expect(s.attackModifier).toBe('normal');
  });

  it('unknown/homebrew condition contributes nothing', () => {
    const s = deriveState('5e', 30, [cond('Inspired by bards')]);
    expect(s).toMatchObject({ speed: 30, attackModifier: 'normal', incapacitated: false });
    expect(s.badges).toEqual([]);
  });
});

describe('deriveState (pf2e)', () => {
  it('frightened contributes a numeric status penalty equal to its value', () => {
    const s = deriveState('pf2e', 25, [cond('Frightened', 2)]);
    expect(s.statusPenalty).toBe(2);
    expect(s.badges).toContain('−2 status');
  });

  it('status penalties do not stack — worst value wins', () => {
    const s = deriveState('pf2e', 25, [cond('Frightened', 1), cond('Sickened', 3)]);
    expect(s.statusPenalty).toBe(3);
  });

  it('grabbed zeroes speed and grants advantage to attackers', () => {
    const s = deriveState('pf2e', 25, [cond('Grabbed')]);
    expect(s.speed).toBe(0);
    expect(s.attacksAgainstModifier).toBe('advantage');
  });
});

describe('concentrationDC', () => {
  it('is half the damage, floored, minimum 10', () => {
    expect(concentrationDC(8)).toBe(10); // floor(4)=4 → min 10
    expect(concentrationDC(22)).toBe(11);
    expect(concentrationDC(40)).toBe(20);
  });
});
