/**
 * Browser Analytics Client
 *
 * Tracks events from browser environments with automatic metadata collection.
 */

import type { EventMetadata } from '../types';
import { BatchQueue, type BatchQueueConfig } from './BatchQueue';
import { collectBrowserMetadata } from './metadata';

/** Simplified tracking event for client SDK */
interface TrackingEvent {
  eventType: string;
  timestamp: string;
  sessionId: string;
  userId?: string;
  properties: Record<string, unknown>;
  metadata: EventMetadata;
  [key: string]: unknown;
}

export interface AnalyticsClientConfig {
  /** Analytics collector endpoint URL */
  endpoint: string;
  /** Batch configuration */
  batch?: Partial<BatchQueueConfig>;
  /** Whether to automatically collect browser metadata */
  autoCollectMetadata?: boolean;
  /** Custom headers to include in requests */
  headers?: Record<string, string>;
  /** Enable debug logging */
  debug?: boolean;
}

export class AnalyticsClient {
  private readonly endpoint: string;
  private readonly queue: BatchQueue;
  private readonly autoCollectMetadata: boolean;
  private readonly headers: Record<string, string>;
  private readonly debug: boolean;
  private sessionId: string;
  private userId: string | null = null;

  constructor(config: AnalyticsClientConfig) {
    this.endpoint = config.endpoint;
    this.autoCollectMetadata = config.autoCollectMetadata ?? true;
    this.headers = config.headers ?? {};
    this.debug = config.debug ?? false;
    this.sessionId = this.generateSessionId();

    this.queue = new BatchQueue({
      maxSize: config.batch?.maxSize ?? 10,
      maxWait: config.batch?.maxWait ?? 5000,
      onFlush: (events) => this.sendEvents(events as TrackingEvent[]),
    });
  }

  /**
   * Identify the current user
   */
  identify(userId: string, traits?: Record<string, unknown>): void {
    this.userId = userId;
    this.track('identify', { userId, traits });
  }

  /**
   * Track an event
   */
  track(eventType: string, properties?: Record<string, unknown>): void {
    const event: TrackingEvent = {
      eventType,
      timestamp: new Date().toISOString(),
      sessionId: this.sessionId,
      userId: this.userId ?? undefined,
      properties: properties ?? {},
      metadata: this.autoCollectMetadata ? collectBrowserMetadata() : {},
    };

    if (this.debug) {
      console.log('[Analytics] Track:', event);
    }

    this.queue.add(event);
  }

  /**
   * Track a page view
   */
  page(name?: string, properties?: Record<string, unknown>): void {
    this.track('page_view', {
      name: name ?? document.title,
      url: window.location.href,
      path: window.location.pathname,
      referrer: document.referrer,
      ...properties,
    });
  }

  /**
   * Flush pending events immediately
   */
  async flush(): Promise<void> {
    await this.queue.flush();
  }

  /**
   * Reset the session (e.g., on logout)
   */
  reset(): void {
    this.userId = null;
    this.sessionId = this.generateSessionId();
  }

  private generateSessionId(): string {
    return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
  }

  private async sendEvents(events: TrackingEvent[]): Promise<void> {
    if (events.length === 0) return;

    try {
      const response = await fetch(`${this.endpoint}/collect`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          ...this.headers,
        },
        body: JSON.stringify({ events }),
      });

      if (!response.ok) {
        throw new Error(`Analytics request failed: ${response.status}`);
      }

      if (this.debug) {
        console.log(`[Analytics] Sent ${events.length} events`);
      }
    } catch (error) {
      console.error('[Analytics] Failed to send events:', error);
      // Events are lost on failure - could implement retry/persistence
    }
  }
}
