/**
 * In-Memory Media Resolver Adapter
 * 
 * Stub implementation for testing purposes.
 * Resolves MediaReference objects to fake URLs without external dependencies.
 * 
 * Part of the adapters layer, implementing the MediaResolverPort interface.
 */

import { MediaResolverPort } from '@core/ports/media/MediaResolverPort';
import { MediaReference } from '@core/domain/media/MediaReference';

/**
 * Configuration for InMemoryMediaResolverAdapter
 */
export interface InMemoryMediaResolverConfig {
  /**
   * Base URL to use for generated URLs
   * @default 'https://fake-media.example.com'
   */
  baseUrl?: string;
  
  /**
   * Whether to simulate network delays
   * @default false
   */
  simulateDelay?: boolean;
  
  /**
   * Delay in milliseconds when simulateDelay is true
   * @default 50
   */
  delayMs?: number;
  
  /**
   * Whether to return null for certain reference types (simulating missing media)
   * @default false
   */
  simulateMissingMedia?: boolean;
}

/**
 * In-Memory Media Resolver Adapter
 * 
 * Stub implementation that resolves media references to fake URLs.
 * Designed for use in tests and development environments.
 * 
 * @example
 * ```typescript
 * const adapter = new InMemoryMediaResolverAdapter({
 *   baseUrl: 'https://test.example.com',
 *   simulateDelay: true
 * });
 * 
 * const ref = MediaReference.createSystemDefault('avatar');
 * const url = await adapter.resolve(ref);
 * // Returns: '/media/default/male-default-avatar.png'
 * ```
 */
export class InMemoryMediaResolverAdapter implements MediaResolverPort {
  private readonly config: Required<InMemoryMediaResolverConfig>;

  constructor(config: InMemoryMediaResolverConfig = {}) {
    this.config = {
      baseUrl: config.baseUrl ?? 'https://fake-media.example.com',
      simulateDelay: config.simulateDelay ?? false,
      delayMs: config.delayMs ?? 50,
      simulateMissingMedia: config.simulateMissingMedia ?? false,
    };
  }

  /**
   * Resolve a media reference to a path-only URL
   * 
   * @param ref - The media reference to resolve
   * @returns Promise resolving to path string or null
   */
  async resolve(ref: MediaReference): Promise<string | null> {
    // Simulate network delay if configured
    if (this.config.simulateDelay) {
      await this.delay(this.config.delayMs);
    }

    // Simulate missing media for some cases
    if (this.config.simulateMissingMedia && this.shouldReturnNull()) {
      return null;
    }

    switch (ref.type) {
      case 'system-default':
        let filename: string;
        if (ref.variant === 'avatar' && ref.avatarVariant) {
          filename = `${ref.avatarVariant}-default-avatar.png`;
        } else if (ref.variant === 'avatar') {
          filename = `neutral-default-avatar.png`;
        } else {
          filename = `${ref.variant}.png`;
        }
        return `/media/default/${filename}`;
      
      case 'generated':
        // Parse the generationRequestId to extract type and id
        // Format: "{type}-{id}" where id can contain hyphens
        if (ref.generationRequestId) {
          const firstHyphenIndex = ref.generationRequestId.indexOf('-');
          if (firstHyphenIndex !== -1) {
            const type = ref.generationRequestId.substring(0, firstHyphenIndex);
            const id = ref.generationRequestId.substring(firstHyphenIndex + 1);
            
            // Use the correct API routes
            if (type === 'team') {
              return `/media/teams/${id}/logo`;
            } else if (type === 'league') {
              return `/media/leagues/${id}/logo`;
            } else if (type === 'driver') {
              return `/media/avatar/${id}`;
            }
            // Fallback for other types
            return `/media/generated/${type}/${id}`;
          }
        }
        // Fallback for unexpected format
        return null;
      
      case 'uploaded':
        return `/media/uploaded/${ref.mediaId}`;
      
      case 'none':
        return null;
      
      default:
        return null;
    }
  }

  /**
   * Simulate network delay
   */
  private delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /**
   * Determine if this reference should return null (simulating missing media)
   */
  private shouldReturnNull(): boolean {
    // Randomly return null for 20% of cases
    return Math.random() < 0.2;
  }

  /**
   * Get the configured base URL
   */
  getBaseUrl(): string {
    return this.config.baseUrl;
  }

  /**
   * Update configuration
   */
  updateConfig(config: Partial<InMemoryMediaResolverConfig>): void {
    Object.assign(this.config, config);
  }

  /**
   * Reset to default configuration
   */
  reset(): void {
    this.config.baseUrl = 'https://fake-media.example.com';
    this.config.simulateDelay = false;
    this.config.delayMs = 50;
    this.config.simulateMissingMedia = false;
  }
}

/**
 * Factory function to create a configured in-memory resolver
 */
export function createInMemoryResolver(
  config: InMemoryMediaResolverConfig = {}
): MediaResolverPort {
  return new InMemoryMediaResolverAdapter(config);
}

/**
 * Pre-configured resolver for common test scenarios
 */
export const TestResolvers = {
  /**
   * Fast resolver with no delays
   */
  fast: () => new InMemoryMediaResolverAdapter({
    baseUrl: 'https://test.example.com',
    simulateDelay: false,
  }),

  /**
   * Slow resolver that simulates network latency
   */
  slow: () => new InMemoryMediaResolverAdapter({
    baseUrl: 'https://test.example.com',
    simulateDelay: true,
    delayMs: 200,
  }),

  /**
   * Unreliable resolver that sometimes returns null
   */
  unreliable: () => new InMemoryMediaResolverAdapter({
    baseUrl: 'https://test.example.com',
    simulateMissingMedia: true,
  }),

  /**
   * Custom base URL resolver
   */
  withBaseUrl: (baseUrl: string) => new InMemoryMediaResolverAdapter({
    baseUrl,
    simulateDelay: false,
  }),

  /**
   * Local development resolver
   */
  local: () => new InMemoryMediaResolverAdapter({
    baseUrl: 'http://localhost:3000/media',
    simulateDelay: false,
  }),
} as const;