import type {
  ViewEventData,
  EngagementEventData,
} from './types';

export interface BackendAnalyticsConfig {
  apiBaseUrl: string;
  appName: string;
  /** Write key sent as X-Write-Key header for collector authentication. Required in production. */
  writeKey?: string;
  enableDebugLogging?: boolean;
}

/**
 * Backend analytics client for server-side event tracking
 * Uses fire-and-forget pattern to avoid blocking request processing
 */
export class BackendAnalyticsClient {
  private config: Required<BackendAnalyticsConfig>;

  constructor(config: BackendAnalyticsConfig) {
    this.config = {
      enableDebugLogging: false,
      writeKey: undefined,
      ...config,
    };
  }

  /**
   * Track a view event (fire-and-forget)
   */
  trackView(data: Omit<ViewEventData, 'app'>): void {
    this.sendEvent('view', {
      ...data,
      app: this.config.appName,
    }).catch((error) => {
      if (this.config.enableDebugLogging) {
        console.error('[Analytics] Failed to track view:', error);
      }
    });
  }

  /**
   * Track an engagement event (fire-and-forget)
   */
  trackEngagement(data: EngagementEventData): void {
    this.sendEvent('engagement', data).catch((error) => {
      if (this.config.enableDebugLogging) {
        console.error('[Analytics] Failed to track engagement:', error);
      }
    });
  }

  /**
   * Track an API call event (specialized view event)
   */
  trackApiCall(data: {
    endpoint: string;
    method: string;
    userId?: string;
    statusCode: number;
    duration?: number;
    ipAddress?: string;
  }): void {
    this.trackView({
      contentId: `${data.method}:${data.endpoint}`,
      contentType: 'post', // Using 'post' as generic content type for API calls
      userId: data.userId,
      sessionId: this.generateSessionId(),
      duration: data.duration,
      ipAddress: data.ipAddress,
      deviceType: 'desktop', // Backend calls don't have device type
    });
  }

  /**
   * Track a business event (specialized engagement event)
   */
  trackBusinessEvent(data: {
    userId: string;
    eventType: 'message_sent' | 'message_received' | 'stream_started' | 'stream_ended' | 'payment_processed';
    targetId: string;
    metadata?: Record<string, unknown>;
  }): void {
    // Map business events to engagement metric types
    const metricTypeMap: Record<typeof data.eventType, EngagementEventData['metricType']> = {
      message_sent: 'comment', // Using comment as proxy for communication
      message_received: 'comment',
      stream_started: 'subscribe', // Using subscribe as proxy for stream engagement
      stream_ended: 'subscribe',
      payment_processed: 'purchase',
    };

    this.trackEngagement({
      userId: data.userId,
      metricType: metricTypeMap[data.eventType],
      targetId: data.targetId,
      targetType: 'content', // Generic target type for business events
      metadata: {
        ...data.metadata,
        businessEventType: data.eventType,
      },
    });
  }

  private async sendEvent(type: 'view' | 'engagement', data: ViewEventData | EngagementEventData): Promise<void> {
    const endpoint = type === 'view' ? '/analytics/track/view' : '/analytics/track/engagement';
    const headers: Record<string, string> = { 'Content-Type': 'application/json' };
    if (this.config.writeKey) headers['X-Write-Key'] = this.config.writeKey;

    try {
      const response = await fetch(`${this.config.apiBaseUrl}${endpoint}`, {
        method: 'POST',
        headers,
        body: JSON.stringify(data),
        signal: AbortSignal.timeout(5000), // 5 second timeout
      });

      if (!response.ok && this.config.enableDebugLogging) {
        console.warn(`[Analytics] Failed to track ${type}: ${response.status} ${response.statusText}`);
      }
    } catch (error) {
      // Silently fail in production, log in debug mode
      if (this.config.enableDebugLogging) {
        console.error(`[Analytics] Error tracking ${type}:`, error);
      }
    }
  }

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