import { describe, it, expect } from 'vitest';
import { addActivityLogEntry } from '../utils/activity-log';
import type { ActivityEventType, ActivityLogEntry } from '../types';

// ─── addActivityLogEntry ──────────────────────────────────────────────────────

describe('addActivityLogEntry', () => {
  it('should add an entry to an empty log', () => {
    const state = { activityLog: [] };
    const result = addActivityLogEntry(state, 'combat', 'Defeated an enemy');
    expect(result.length).toBe(1);
    expect(result[0].message).toBe('Defeated an enemy');
    expect(result[0].eventType).toBe('combat');
  });

  it('should prepend new entries (newest first)', () => {
    const state = {
      activityLog: [
        { id: 'old_1', timestamp: 1000, eventType: 'combat' as const, message: 'Old event' },
      ],
    };
    const result = addActivityLogEntry(state, 'crafting', 'Crafted an item');
    expect(result.length).toBe(2);
    expect(result[0].message).toBe('Crafted an item');
    expect(result[1].message).toBe('Old event');
  });

  it('should include an id on the new entry', () => {
    const state = { activityLog: [] };
    const result = addActivityLogEntry(state, 'combat', 'Test');
    expect(result[0].id).toBeDefined();
    expect(typeof result[0].id).toBe('string');
    expect(result[0].id.length).toBeGreaterThan(0);
  });

  it('should include a timestamp on the new entry', () => {
    const before = Date.now();
    const state = { activityLog: [] };
    const result = addActivityLogEntry(state, 'combat', 'Test');
    const after = Date.now();
    expect(result[0].timestamp).toBeGreaterThanOrEqual(before);
    expect(result[0].timestamp).toBeLessThanOrEqual(after);
  });

  it('should include optional details', () => {
    const state = { activityLog: [] };
    const details = { floor: 10, enemy: 'Fire Guardian' };
    const result = addActivityLogEntry(state, 'combat', 'Boss defeated', details);
    expect(result[0].details).toEqual(details);
  });

  it('should work without details', () => {
    const state = { activityLog: [] };
    const result = addActivityLogEntry(state, 'combat', 'Test');
    expect(result[0].details).toBeUndefined();
  });

  it('should keep only the last 50 entries', () => {
    // Create a log with 50 existing entries
    const existing: ActivityLogEntry[] = [];
    for (let i = 0; i < 50; i++) {
      existing.push({
        id: `entry_${i}`,
        timestamp: i,
        eventType: 'combat',
        message: `Entry ${i}`,
      });
    }
    const state = { activityLog: existing };
    const result = addActivityLogEntry(state, 'combat', 'New entry');

    expect(result.length).toBe(50);
    expect(result[0].message).toBe('New entry');
    // With 50 existing entries, the function takes first 49 and prepends new
    // So the entries are: [new, entry_0, entry_1, ..., entry_48] (50 total)
    // The oldest (entry_49) gets dropped, not entry_0
    expect(result.some(e => e.id === 'entry_49')).toBe(false);
    // entry_0 should still be there (it's now the second entry)
    expect(result.some(e => e.id === 'entry_0')).toBe(true);
  });

  it('should handle adding to a log with exactly 49 entries', () => {
    const existing: ActivityLogEntry[] = [];
    for (let i = 0; i < 49; i++) {
      existing.push({
        id: `entry_${i}`,
        timestamp: i,
        eventType: 'combat',
        message: `Entry ${i}`,
      });
    }
    const state = { activityLog: existing };
    const result = addActivityLogEntry(state, 'combat', 'New entry');
    expect(result.length).toBe(50);
  });

  it('should not mutate the original log', () => {
    const state = {
      activityLog: [
        { id: 'old_1', timestamp: 1000, eventType: 'combat' as const, message: 'Old event' },
      ],
    };
    const originalLength = state.activityLog.length;
    addActivityLogEntry(state, 'crafting', 'New event');
    expect(state.activityLog.length).toBe(originalLength);
  });

  it('should handle various event types', () => {
    const state: { activityLog: ActivityLogEntry[] } = { activityLog: [] };
    const types: ActivityEventType[] = ['combat', 'damage_dealt', 'enemy_defeated', 'floor_cleared', 'spell_cast'];
    let current = state;
    for (const eventType of types) {
      const result = addActivityLogEntry(current, eventType, `Event: ${eventType}`);
      expect(result[0].eventType).toBe(eventType);
      current = { activityLog: result };
    }
    expect(current.activityLog.length).toBe(types.length);
  });
});
