import { ICalendarEvent, EntityType, IEventBus } from '../../types/CalendarTypes';
import { EventStore } from './EventStore';
import { EventSerialization } from './EventSerialization';
import { BaseEntityService } from '../BaseEntityService';
import { IndexedDBContext } from '../IndexedDBContext';

/**
 * EventService - CRUD operations for calendar events in IndexedDB
 *
 * Extends BaseEntityService for shared CRUD and sync logic.
 * Provides event-specific query methods.
 */
export class EventService extends BaseEntityService<ICalendarEvent> {
  readonly storeName = EventStore.STORE_NAME;
  readonly entityType: EntityType = 'Event';

  constructor(context: IndexedDBContext, eventBus: IEventBus) {
    super(context, eventBus);
  }

  protected serialize(event: ICalendarEvent): unknown {
    return EventSerialization.serialize(event);
  }

  protected deserialize(data: unknown): ICalendarEvent {
    return EventSerialization.deserialize(data as Record<string, unknown>);
  }

  /**
   * Get events within a date range
   */
  async getByDateRange(start: Date, end: Date): Promise<ICalendarEvent[]> {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], 'readonly');
      const store = transaction.objectStore(this.storeName);
      const index = store.index('start');

      const range = IDBKeyRange.lowerBound(start.toISOString());
      const request = index.getAll(range);

      request.onsuccess = () => {
        const data = request.result as unknown[];
        const events = data
          .map(item => this.deserialize(item))
          .filter(event => event.start <= end);
        resolve(events);
      };

      request.onerror = () => {
        reject(new Error(`Failed to get events by date range: ${request.error}`));
      };
    });
  }

  /**
   * Get events for a specific resource
   */
  async getByResource(resourceId: string): Promise<ICalendarEvent[]> {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], 'readonly');
      const store = transaction.objectStore(this.storeName);
      const index = store.index('resourceId');
      const request = index.getAll(resourceId);

      request.onsuccess = () => {
        const data = request.result as unknown[];
        const events = data.map(item => this.deserialize(item));
        resolve(events);
      };

      request.onerror = () => {
        reject(new Error(`Failed to get events for resource ${resourceId}: ${request.error}`));
      };
    });
  }

  /**
   * Get events for a resource within a date range
   */
  async getByResourceAndDateRange(resourceId: string, start: Date, end: Date): Promise<ICalendarEvent[]> {
    const resourceEvents = await this.getByResource(resourceId);
    return resourceEvents.filter(event => event.start >= start && event.start <= end);
  }
}
