/**
 * Event Store - Zustand store for project events
 *
 * Manages real-time events received via SSE with:
 * - Event buffer (configurable, default 100 events)
 * - Per-project event management
 * - Event filtering utilities
 *
 * @module lib/stores/eventStore
 */

import { create } from 'zustand';
import type { ProjectEvent, EventType } from '@/lib/types/events';

// ============================================================================
// Constants
// ============================================================================

/** Maximum number of events to keep in buffer per project */
const DEFAULT_MAX_EVENTS = 100;

// ============================================================================
// Types
// ============================================================================

interface EventState {
  /** Events indexed by project ID */
  eventsByProject: Record<string, ProjectEvent[]>;

  /** Maximum events to keep per project */
  maxEvents: number;
}

interface EventActions {
  /**
   * Add an event to the store
   * @param event - The event to add
   */
  addEvent: (event: ProjectEvent) => void;

  /**
   * Add multiple events at once
   * @param events - Array of events to add
   */
  addEvents: (events: ProjectEvent[]) => void;

  /**
   * Clear all events for a specific project
   * @param projectId - Project ID to clear events for
   */
  clearProjectEvents: (projectId: string) => void;

  /**
   * Clear all events from the store
   */
  clearAllEvents: () => void;

  /**
   * Get events for a specific project
   * @param projectId - Project ID
   * @returns Array of events for the project
   */
  getProjectEvents: (projectId: string) => ProjectEvent[];

  /**
   * Get events filtered by type
   * @param projectId - Project ID
   * @param types - Event types to filter by
   * @returns Filtered array of events
   */
  getFilteredEvents: (projectId: string, types: EventType[]) => ProjectEvent[];

  /**
   * Set the maximum number of events to keep per project
   * @param max - Maximum event count
   */
  setMaxEvents: (max: number) => void;
}

export type EventStore = EventState & EventActions;

// ============================================================================
// Store Implementation
// ============================================================================

export const useEventStore = create<EventStore>((set, get) => ({
  // Initial state
  eventsByProject: {},
  maxEvents: DEFAULT_MAX_EVENTS,

  addEvent: (event: ProjectEvent) => {
    set((state) => {
      const projectId = event.project_id;
      const existingEvents = state.eventsByProject[projectId] || [];

      // Check for duplicate event IDs
      if (existingEvents.some((e) => e.id === event.id)) {
        return state; // Skip duplicate
      }

      // Add new event and trim to max
      const updatedEvents = [...existingEvents, event].slice(-state.maxEvents);

      return {
        eventsByProject: {
          ...state.eventsByProject,
          [projectId]: updatedEvents,
        },
      };
    });
  },

  addEvents: (events: ProjectEvent[]) => {
    if (events.length === 0) return;

    set((state) => {
      const updatedEventsByProject = { ...state.eventsByProject };

      // Group events by project
      const eventsByProjectId = events.reduce(
        (acc, event) => {
          if (!acc[event.project_id]) {
            acc[event.project_id] = [];
          }
          acc[event.project_id].push(event);
          return acc;
        },
        {} as Record<string, ProjectEvent[]>
      );

      // Merge events for each project
      for (const [projectId, newEvents] of Object.entries(eventsByProjectId)) {
        const existingEvents = updatedEventsByProject[projectId] || [];

        // Filter out duplicates
        const existingIds = new Set(existingEvents.map((e) => e.id));
        const uniqueNewEvents = newEvents.filter((e) => !existingIds.has(e.id));

        // Merge and trim
        updatedEventsByProject[projectId] = [...existingEvents, ...uniqueNewEvents].slice(
          -state.maxEvents
        );
      }

      return { eventsByProject: updatedEventsByProject };
    });
  },

  clearProjectEvents: (projectId: string) => {
    set((state) => {
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      const { [projectId]: _removed, ...rest } = state.eventsByProject;
      return { eventsByProject: rest };
    });
  },

  clearAllEvents: () => {
    set({ eventsByProject: {} });
  },

  getProjectEvents: (projectId: string) => {
    return get().eventsByProject[projectId] || [];
  },

  getFilteredEvents: (projectId: string, types: EventType[]) => {
    const events = get().eventsByProject[projectId] || [];
    if (types.length === 0) return events;

    const typeSet = new Set(types);
    return events.filter((event) => typeSet.has(event.type));
  },

  setMaxEvents: (max: number) => {
    if (max < 1) {
      console.warn(`Invalid maxEvents value: ${max}, using default: ${DEFAULT_MAX_EVENTS}`);
      max = DEFAULT_MAX_EVENTS;
    }

    set((state) => {
      // Trim existing events if necessary
      const trimmedEventsByProject: Record<string, ProjectEvent[]> = {};

      for (const [projectId, events] of Object.entries(state.eventsByProject)) {
        trimmedEventsByProject[projectId] = events.slice(-max);
      }

      return {
        maxEvents: max,
        eventsByProject: trimmedEventsByProject,
      };
    });
  },
}));

// ============================================================================
// Selector Hooks
// ============================================================================

/**
 * Hook to get events for a specific project
 * @param projectId - Project ID
 * @returns Array of events for the project
 */
export function useProjectEventsFromStore(projectId: string): ProjectEvent[] {
  return useEventStore((state) => state.eventsByProject[projectId] || []);
}

/**
 * Hook to get the latest event for a project
 * @param projectId - Project ID
 * @returns Latest event or undefined
 */
export function useLatestEvent(projectId: string): ProjectEvent | undefined {
  const events = useEventStore((state) => state.eventsByProject[projectId] || []);
  return events[events.length - 1];
}

/**
 * Hook to get event count for a project
 * @param projectId - Project ID
 * @returns Number of events
 */
export function useEventCount(projectId: string): number {
  return useEventStore((state) => (state.eventsByProject[projectId] || []).length);
}
