import type { AnalyticsConfig, ViewEventData, EngagementEventData } from '../types';
import type { ModuleMetadata, Type } from '@nestjs/common';

/**
 * Configuration options for the AnalyticsModule
 */
export interface AnalyticsModuleOptions extends AnalyticsConfig {
  /**
   * Whether to enable global interceptor for all routes
   * @default false
   */
  enableGlobalInterceptor?: boolean;
}

/**
 * Factory interface for creating AnalyticsModuleOptions asynchronously
 */
export interface AnalyticsOptionsFactory {
  createAnalyticsOptions(): Promise<AnalyticsModuleOptions> | AnalyticsModuleOptions;
}

/**
 * Async configuration options for AnalyticsModule
 */
export interface AnalyticsModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
  /**
   * Factory function to create options
   */
  useFactory?: (...args: unknown[]) => Promise<AnalyticsModuleOptions> | AnalyticsModuleOptions;
  /**
   * Dependencies to inject into the factory function
   */
  inject?: unknown[];
  /**
   * Use an existing provider that implements AnalyticsOptionsFactory
   */
  useExisting?: Type<AnalyticsOptionsFactory>;
  /**
   * Use a class that implements AnalyticsOptionsFactory
   */
  useClass?: Type<AnalyticsOptionsFactory>;
}

/**
 * Options for the @TrackAnalytics() decorator
 */
export interface TrackAnalyticsOptions {
  /**
   * Type of analytics event to track
   */
  eventType: 'view' | 'engagement';

  /**
   * Content type for view events
   */
  contentType?: ViewEventData['contentType'];

  /**
   * Metric type for engagement events
   */
  metricType?: EngagementEventData['metricType'];

  /**
   * Target type for engagement events
   */
  targetType?: EngagementEventData['targetType'];

  /**
   * Function to extract contentId from method arguments
   * @param args - Method arguments
   * @returns Content ID or target ID
   */
  idExtractor?: (...args: unknown[]) => string;

  /**
   * Function to extract userId from execution context
   * @param context - Execution context or request object
   * @returns User ID if available
   */
  userIdExtractor?: (context: unknown) => string | undefined;

  /**
   * Additional metadata to include with the event
   */
  metadata?: Record<string, unknown>;
}

/**
 * Tracking context passed to helper functions
 */
export interface TrackingContext {
  /**
   * Method name being tracked
   */
  method: string;

  /**
   * Class name being tracked
   */
  className: string;

  /**
   * Method arguments
   */
  args: unknown[];

  /**
   * Execution result (available in after tracking)
   */
  result?: unknown;

  /**
   * Error if method threw (available in error tracking)
   */
  error?: Error;

  /**
   * HTTP request object (if available)
   */
  request?: {
    headers: Record<string, string | string[]>;
    ip?: string;
    method?: string;
    url?: string;
  };

  /**
   * User information from authentication
   */
  user?: {
    id: string;
    [key: string]: unknown;
  };
}
