import { Direction, EventMapKeys } from '../types';
import Api from './api';
import type { AnalyticsPayload } from '../types/api';
import { Helpers } from './helpers';
import { AnalyticsConsent } from './analyticsConsent';
import { Identity } from './identity';

export interface AnalyticsEventData {
  event_widget_id: string;
  event_post_id?: string;
  event_product_id?: string;
  event_direction?: Direction;
  event_position?: number;
}

export class Analytics {
  private static eventQueue: AnalyticsPayload[] = [];

  private static batchTimer: ReturnType<typeof setTimeout> | null = null;

  private static readonly BATCH_INTERVAL_MS = 5000;

  private static readonly IMMEDIATE_FLUSH_EVENTS: Set<EventMapKeys> = new Set([
    'packshotClicked',
    'productClicked',
  ]);

  public static async trackEvent<K extends EventMapKeys>(params: {
    eventName: K;
    data: AnalyticsEventData;
  }): Promise<void> {
    const { eventName, data } = params;

    const hasConsent = AnalyticsConsent.has();
    const identity = hasConsent ? Identity.getIdentity() : null;
    if (hasConsent && identity) {
      Identity.touchSession();
    }

    const payload: AnalyticsPayload = {
      eventName: eventName as string,
      widgetId: data.event_widget_id,
      postId: data.event_post_id,
      productId: data.event_product_id,
      direction: data.event_direction,
      position: data.event_position,
      timestamp: new Date().toISOString(),
      userAgent: navigator.userAgent,
      referrer: document.referrer || undefined,
      pageLocation: window.location?.href || undefined,
      pageTitle: document.title || undefined,
      deviceCategory: Helpers.getDeviceCategory(),
      consent: hasConsent,
      identity:
        hasConsent && identity
          ? {
              visitor_id: identity.visitorId,
              session_id: identity.sessionId,
            }
          : undefined,
    };

    this.eventQueue.push(payload);

    if (this.IMMEDIATE_FLUSH_EVENTS.has(eventName)) {
      await this.flushImmediately();
      return;
    }

    if (!this.batchTimer) {
      this.batchTimer = setTimeout(() => {
        void this.sendBatch();
      }, this.BATCH_INTERVAL_MS);
    }
  }

  private static clearBatchTimer(): void {
    if (this.batchTimer) {
      clearTimeout(this.batchTimer);
      this.batchTimer = null;
    }
  }

  private static async flushImmediately(): Promise<void> {
    this.clearBatchTimer();
    await this.sendBatch();
  }

  private static async sendBatch(): Promise<void> {
    if (this.eventQueue.length === 0) return;

    const events = [...this.eventQueue];
    this.eventQueue = [];
    this.batchTimer = null;

    try {
      await Api.trackAnalyticsBatch(events);
    } catch (error) {
      console.warn('Failed to send analytics batch:', error);
    }
  }
}
