/**
 * Tests for Event Store
 */

import { useEventStore } from '@/lib/stores/eventStore';
import { EventType, type ProjectEvent } from '@/lib/types/events';

/**
 * Helper to create mock event
 */
function createMockEvent(overrides: Partial<ProjectEvent> = {}): ProjectEvent {
  return {
    id: `event-${Math.random().toString(36).substr(2, 9)}`,
    type: EventType.AGENT_MESSAGE,
    timestamp: new Date().toISOString(),
    project_id: 'project-123',
    actor_id: 'agent-456',
    actor_type: 'agent',
    payload: { message: 'Test message' },
    ...overrides,
  };
}

describe('Event Store', () => {
  beforeEach(() => {
    // Reset store state
    useEventStore.setState({
      eventsByProject: {},
      maxEvents: 100,
    });
  });

  describe('addEvent', () => {
    it('should add an event to the store', () => {
      const event = createMockEvent();

      useEventStore.getState().addEvent(event);

      const events = useEventStore.getState().getProjectEvents('project-123');
      expect(events).toHaveLength(1);
      expect(events[0]).toEqual(event);
    });

    it('should add events to correct project', () => {
      const event1 = createMockEvent({ project_id: 'project-1' });
      const event2 = createMockEvent({ project_id: 'project-2' });

      useEventStore.getState().addEvent(event1);
      useEventStore.getState().addEvent(event2);

      expect(useEventStore.getState().getProjectEvents('project-1')).toHaveLength(1);
      expect(useEventStore.getState().getProjectEvents('project-2')).toHaveLength(1);
    });

    it('should skip duplicate event IDs', () => {
      const event = createMockEvent({ id: 'unique-id' });

      useEventStore.getState().addEvent(event);
      useEventStore.getState().addEvent(event);

      const events = useEventStore.getState().getProjectEvents('project-123');
      expect(events).toHaveLength(1);
    });

    it('should trim events to maxEvents limit', () => {
      useEventStore.getState().setMaxEvents(5);

      // Add 10 events
      for (let i = 0; i < 10; i++) {
        useEventStore.getState().addEvent(createMockEvent({ id: `event-${i}` }));
      }

      const events = useEventStore.getState().getProjectEvents('project-123');
      expect(events).toHaveLength(5);
      // Should keep the last 5 events
      expect(events[0].id).toBe('event-5');
      expect(events[4].id).toBe('event-9');
    });
  });

  describe('addEvents', () => {
    it('should add multiple events at once', () => {
      const events = [
        createMockEvent({ id: 'event-1' }),
        createMockEvent({ id: 'event-2' }),
        createMockEvent({ id: 'event-3' }),
      ];

      useEventStore.getState().addEvents(events);

      const storedEvents = useEventStore.getState().getProjectEvents('project-123');
      expect(storedEvents).toHaveLength(3);
    });

    it('should handle empty array', () => {
      useEventStore.getState().addEvents([]);

      const events = useEventStore.getState().getProjectEvents('project-123');
      expect(events).toHaveLength(0);
    });

    it('should filter out duplicate events', () => {
      const existingEvent = createMockEvent({ id: 'existing-event' });
      useEventStore.getState().addEvent(existingEvent);

      const newEvents = [
        createMockEvent({ id: 'existing-event' }), // Duplicate
        createMockEvent({ id: 'new-event-1' }),
        createMockEvent({ id: 'new-event-2' }),
      ];

      useEventStore.getState().addEvents(newEvents);

      const storedEvents = useEventStore.getState().getProjectEvents('project-123');
      expect(storedEvents).toHaveLength(3);
    });

    it('should add events to multiple projects', () => {
      const events = [
        createMockEvent({ id: 'event-1', project_id: 'project-1' }),
        createMockEvent({ id: 'event-2', project_id: 'project-2' }),
        createMockEvent({ id: 'event-3', project_id: 'project-1' }),
      ];

      useEventStore.getState().addEvents(events);

      expect(useEventStore.getState().getProjectEvents('project-1')).toHaveLength(2);
      expect(useEventStore.getState().getProjectEvents('project-2')).toHaveLength(1);
    });
  });

  describe('clearProjectEvents', () => {
    it('should clear events for a specific project', () => {
      const event1 = createMockEvent({ project_id: 'project-1' });
      const event2 = createMockEvent({ project_id: 'project-2' });

      useEventStore.getState().addEvent(event1);
      useEventStore.getState().addEvent(event2);

      useEventStore.getState().clearProjectEvents('project-1');

      expect(useEventStore.getState().getProjectEvents('project-1')).toHaveLength(0);
      expect(useEventStore.getState().getProjectEvents('project-2')).toHaveLength(1);
    });

    it('should handle clearing non-existent project', () => {
      expect(() => {
        useEventStore.getState().clearProjectEvents('non-existent');
      }).not.toThrow();
    });
  });

  describe('clearAllEvents', () => {
    it('should clear all events from all projects', () => {
      const event1 = createMockEvent({ project_id: 'project-1' });
      const event2 = createMockEvent({ project_id: 'project-2' });

      useEventStore.getState().addEvent(event1);
      useEventStore.getState().addEvent(event2);

      useEventStore.getState().clearAllEvents();

      expect(useEventStore.getState().getProjectEvents('project-1')).toHaveLength(0);
      expect(useEventStore.getState().getProjectEvents('project-2')).toHaveLength(0);
    });
  });

  describe('getProjectEvents', () => {
    it('should return empty array for non-existent project', () => {
      const events = useEventStore.getState().getProjectEvents('non-existent');
      expect(events).toEqual([]);
    });

    it('should return events for existing project', () => {
      const event = createMockEvent();
      useEventStore.getState().addEvent(event);

      const events = useEventStore.getState().getProjectEvents('project-123');
      expect(events).toHaveLength(1);
      expect(events[0]).toEqual(event);
    });
  });

  describe('getFilteredEvents', () => {
    it('should filter events by type', () => {
      const agentEvent = createMockEvent({ type: EventType.AGENT_MESSAGE });
      const issueEvent = createMockEvent({ type: EventType.ISSUE_CREATED });
      const sprintEvent = createMockEvent({ type: EventType.SPRINT_STARTED });

      useEventStore.getState().addEvents([agentEvent, issueEvent, sprintEvent]);

      const filtered = useEventStore.getState().getFilteredEvents('project-123', [
        EventType.AGENT_MESSAGE,
        EventType.ISSUE_CREATED,
      ]);

      expect(filtered).toHaveLength(2);
      expect(filtered.map((e) => e.type)).toContain(EventType.AGENT_MESSAGE);
      expect(filtered.map((e) => e.type)).toContain(EventType.ISSUE_CREATED);
    });

    it('should return all events when types array is empty', () => {
      const event1 = createMockEvent({ type: EventType.AGENT_MESSAGE });
      const event2 = createMockEvent({ type: EventType.ISSUE_CREATED });

      useEventStore.getState().addEvents([event1, event2]);

      const filtered = useEventStore.getState().getFilteredEvents('project-123', []);
      expect(filtered).toHaveLength(2);
    });

    it('should return empty array for non-existent project', () => {
      const filtered = useEventStore.getState().getFilteredEvents('non-existent', [
        EventType.AGENT_MESSAGE,
      ]);
      expect(filtered).toEqual([]);
    });
  });

  describe('setMaxEvents', () => {
    it('should update maxEvents setting', () => {
      useEventStore.getState().setMaxEvents(50);
      expect(useEventStore.getState().maxEvents).toBe(50);
    });

    it('should use default for invalid values', () => {
      const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation();

      useEventStore.getState().setMaxEvents(0);
      expect(useEventStore.getState().maxEvents).toBe(100); // Default

      useEventStore.getState().setMaxEvents(-5);
      expect(useEventStore.getState().maxEvents).toBe(100); // Default

      expect(consoleWarnSpy).toHaveBeenCalled();
      consoleWarnSpy.mockRestore();
    });

    it('should trim existing events when reducing maxEvents', () => {
      // Add 10 events
      for (let i = 0; i < 10; i++) {
        useEventStore.getState().addEvent(createMockEvent({ id: `event-${i}` }));
      }

      expect(useEventStore.getState().getProjectEvents('project-123')).toHaveLength(10);

      useEventStore.getState().setMaxEvents(5);

      const events = useEventStore.getState().getProjectEvents('project-123');
      expect(events).toHaveLength(5);
      // Should keep the last 5 events
      expect(events[0].id).toBe('event-5');
    });
  });
});
