import { v4 as uuidv4 } from 'uuid'
import { vezaFaker } from '../utils/faker-config'
import { globalConfig } from '../config'
import type { 
  Audio, 
  AudioGenre, 
  AudioMetadata,
  Playlist,
  PlaylistVisibility 
} from '../schemas/database'

/**
 * Audio generation options
 */
export interface AudioGenerationOptions {
  genre?: AudioGenre
  uploadedById?: string
  albumId?: string
  albumTitle?: string
  isPublic?: boolean
  isExplicit?: boolean
  downloadEnabled?: boolean
  withWaveform?: boolean
  withCover?: boolean
  withLyrics?: boolean
  isPopular?: boolean
  releaseDate?: Date
}

/**
 * Album data structure
 */
export interface Album {
  id: string
  title: string
  artist: string
  genre: AudioGenre
  releaseDate: Date
  coverImageUrl?: string
  tracks: Audio[]
  totalDuration: number
  isExplicit: boolean
}

/**
 * Playlist generation options
 */
export interface PlaylistGenerationOptions {
  createdById?: string
  trackCount?: number
  visibility?: PlaylistVisibility
  isCollaborative?: boolean
  withCover?: boolean
  genre?: AudioGenre
  theme?: 'workout' | 'chill' | 'party' | 'focus' | 'random'
}

/**
 * Advanced audio content generator for Veza Platform
 */
export class AudioGenerator {
  private static generatedTracks: Map<string, Audio> = new Map()
  private static generatedAlbums: Map<string, Album> = new Map()
  private static generatedPlaylists: Map<string, Playlist> = new Map()
  private static usedSlugs: Set<string> = new Set()

  /**
   * Generate a single audio track
   */
  static generate(options: AudioGenerationOptions = {}): Audio {
    const genre = options.genre || vezaFaker.music.genre()
    const title = vezaFaker.music.songTitle()
    const artist = vezaFaker.music.artistName()
    const slug = this.generateUniqueSlug(title, artist)
    const metadata = vezaFaker.music.audioMetadata(genre)
    const createdAt = vezaFaker.date.contentCreation(new Date('2024-01-01'))
    const releaseDate = options.releaseDate || vezaFaker.date.releaseDate()
    
    const track: Audio = {
      id: uuidv4(),
      title,
      slug,
      artist,
      albumId: options.albumId,
      albumTitle: options.albumTitle,
      genre,
      subgenre: this.generateSubgenre(genre),
      tags: vezaFaker.music.tags(),
      description: this.generateTrackDescription(title, artist, genre),
      lyrics: options.withLyrics !== false ? this.generateLyrics() : undefined,
      metadata,
      waveformData: options.withWaveform !== false ? vezaFaker.music.waveformData(metadata.duration) : undefined,
      fileUrl: vezaFaker.utils.fileUrl('audio', `${slug}.${metadata.format}`),
      coverImageUrl: options.withCover !== false ? vezaFaker.utils.fileUrl('image', `${slug}-cover.jpg`) : undefined,
      uploadedById: options.uploadedById || uuidv4(), // Will be replaced with real user ID
      isPublic: options.isPublic ?? vezaFaker.datatype.boolean({ probability: 0.8 }),
      isExplicit: options.isExplicit ?? vezaFaker.datatype.boolean({ probability: 0.1 }),
      downloadEnabled: options.downloadEnabled ?? vezaFaker.datatype.boolean({ probability: 0.3 }),
      stats: vezaFaker.stats.audioStats(createdAt, options.isPopular),
      releaseDate,
      createdAt,
      updatedAt: vezaFaker.date.between({ from: createdAt, to: new Date() }),
    }

    this.generatedTracks.set(track.id, track)
    return track
  }

  /**
   * Generate multiple tracks
   */
  static generateBatch(count: number, options: AudioGenerationOptions = {}): Audio[] {
    const tracks: Audio[] = []
    
    for (let i = 0; i < count; i++) {
      tracks.push(this.generate(options))
    }
    
    return tracks
  }

  /**
   * Generate a complete album with tracks
   */
  static generateAlbum(trackCount: number = 10, options: Partial<AudioGenerationOptions> = {}): Album {
    const albumId = uuidv4()
    const albumTitle = vezaFaker.music.albumTitle()
    const artist = vezaFaker.music.artistName()
    const genre = options.genre || vezaFaker.music.genre()
    const releaseDate = options.releaseDate || vezaFaker.date.releaseDate()
    const isExplicit = options.isExplicit ?? vezaFaker.datatype.boolean({ probability: 0.15 })
    
    const tracks: Audio[] = []
    let totalDuration = 0
    
    for (let i = 0; i < trackCount; i++) {
      const track = this.generate({
        ...options,
        albumId,
        albumTitle,
        genre: i === 0 ? genre : (vezaFaker.datatype.boolean({ probability: 0.7 }) ? genre : vezaFaker.music.genre()),
        uploadedById: options.uploadedById || uuidv4(),
        isExplicit: isExplicit || vezaFaker.datatype.boolean({ probability: 0.05 }),
        releaseDate,
      })
      
      // Override artist for consistency (80% same artist, 20% featuring)
      if (vezaFaker.datatype.boolean({ probability: 0.8 })) {
        track.artist = artist
      } else {
        track.artist = `${artist} feat. ${vezaFaker.music.artistName()}`
      }
      
      tracks.push(track)
      totalDuration += track.metadata.duration
    }
    
    const album: Album = {
      id: albumId,
      title: albumTitle,
      artist,
      genre,
      releaseDate,
      coverImageUrl: vezaFaker.utils.fileUrl('image', `${albumId}-album-cover.jpg`),
      tracks,
      totalDuration,
      isExplicit
    }
    
    this.generatedAlbums.set(albumId, album)
    return album
  }

  /**
   * Generate multiple albums
   */
  static generateAlbums(count: number, options: Partial<AudioGenerationOptions> = {}): Album[] {
    const albums: Album[] = []
    
    for (let i = 0; i < count; i++) {
      const trackCount = vezaFaker.number.int({ min: 3, max: 15 })
      albums.push(this.generateAlbum(trackCount, options))
    }
    
    return albums
  }

  /**
   * Generate a playlist
   */
  static generatePlaylist(options: PlaylistGenerationOptions = {}): Playlist {
    const trackCount = options.trackCount || vezaFaker.number.int({ min: 5, max: 50 })
    const theme = options.theme || vezaFaker.helpers.arrayElement(['workout', 'chill', 'party', 'focus', 'random'])
    const title = this.generatePlaylistTitle(theme)
    const slug = this.generateUniqueSlug(title)
    const createdAt = vezaFaker.date.contentCreation(new Date('2024-01-01'))
    
    // Generate track IDs (will be replaced with real track IDs)
    const trackIds = Array.from({ length: trackCount }, () => uuidv4())
    
    const playlist: Playlist = {
      id: uuidv4(),
      title,
      slug,
      description: this.generatePlaylistDescription(title, theme),
      coverImageUrl: options.withCover !== false ? vezaFaker.utils.fileUrl('image', `${slug}-playlist.jpg`) : undefined,
      createdById: options.createdById || uuidv4(),
      visibility: options.visibility || vezaFaker.helpers.arrayElement(['public', 'unlisted', 'private']),
      isCollaborative: options.isCollaborative ?? vezaFaker.datatype.boolean({ probability: 0.1 }),
      tags: this.generatePlaylistTags(theme),
      trackIds,
      stats: {
        followers: vezaFaker.number.int({ min: 0, max: 500 }),
        plays: vezaFaker.number.int({ min: 0, max: 10000 }),
        shares: vezaFaker.number.int({ min: 0, max: 100 }),
      },
      createdAt,
      updatedAt: vezaFaker.date.between({ from: createdAt, to: new Date() }),
    }
    
    this.generatedPlaylists.set(playlist.id, playlist)
    return playlist
  }

  /**
   * Generate multiple playlists
   */
  static generatePlaylists(count: number, options: PlaylistGenerationOptions = {}): Playlist[] {
    const playlists: Playlist[] = []
    
    for (let i = 0; i < count; i++) {
      playlists.push(this.generatePlaylist(options))
    }
    
    return playlists
  }

  /**
   * Generate genre-specific content
   */
  static generateGenreCollection(genre: AudioGenre, trackCount: number = 20): {
    tracks: Audio[]
    albums: Album[]
    playlists: Playlist[]
  } {
    // Generate individual tracks
    const tracks = this.generateBatch(Math.floor(trackCount * 0.6), { genre })
    
    // Generate albums
    const albumCount = Math.floor(trackCount * 0.3 / 8) // Average 8 tracks per album
    const albums = this.generateAlbums(albumCount, { genre })
    
    // Add album tracks to tracks collection
    albums.forEach(album => {
      tracks.push(...album.tracks)
    })
    
    // Generate playlists
    const playlistCount = Math.max(1, Math.floor(trackCount / 10))
    const playlists = this.generatePlaylists(playlistCount, { genre })
    
    return { tracks, albums, playlists }
  }

  /**
   * Generate content for specific user roles
   */
  static generateUserContent(userId: string, role: 'artist' | 'producer' | 'user'): {
    tracks: Audio[]
    albums: Album[]
    playlists: Playlist[]
  } {
    const content = {
      artist: () => {
        const trackCount = vezaFaker.number.int({ min: 5, max: 30 })
        const albumCount = vezaFaker.number.int({ min: 1, max: 4 })
        const playlistCount = vezaFaker.number.int({ min: 2, max: 8 })
        
        return {
          tracks: this.generateBatch(trackCount, { 
            uploadedById: userId,
            isPopular: vezaFaker.datatype.boolean({ probability: 0.3 })
          }),
          albums: this.generateAlbums(albumCount, { uploadedById: userId }),
          playlists: this.generatePlaylists(playlistCount, { createdById: userId })
        }
      },
      producer: () => {
        const trackCount = vezaFaker.number.int({ min: 10, max: 50 })
        const albumCount = vezaFaker.number.int({ min: 2, max: 6 })
        const playlistCount = vezaFaker.number.int({ min: 5, max: 15 })
        
        return {
          tracks: this.generateBatch(trackCount, { 
            uploadedById: userId,
            genre: vezaFaker.helpers.arrayElement(['electronic', 'hip-hop', 'pop']),
            downloadEnabled: true
          }),
          albums: this.generateAlbums(albumCount, { uploadedById: userId }),
          playlists: this.generatePlaylists(playlistCount, { 
            createdById: userId,
            isCollaborative: vezaFaker.datatype.boolean({ probability: 0.3 })
          })
        }
      },
      user: () => ({
        tracks: [],
        albums: [],
        playlists: this.generatePlaylists(vezaFaker.number.int({ min: 1, max: 5 }), { 
          createdById: userId,
          visibility: vezaFaker.helpers.arrayElement(['private', 'unlisted', 'public'])
        })
      })
    }
    
    return content[role]()
  }

  /**
   * Private helper methods
   */
  private static generateUniqueSlug(title: string, artist?: string): string {
    let baseSlug = vezaFaker.utils.slug(artist ? `${artist} ${title}` : title)
    let slug = baseSlug
    let counter = 1
    
    while (this.usedSlugs.has(slug)) {
      slug = `${baseSlug}-${counter}`
      counter++
    }
    
    this.usedSlugs.add(slug)
    return slug
  }

  private static generateSubgenre(genre: AudioGenre): string | undefined {
    const subgenres: Record<AudioGenre, string[]> = {
      rock: ['alternative', 'classic', 'indie', 'progressive', 'punk'],
      pop: ['synth-pop', 'indie-pop', 'electro-pop', 'dance-pop'],
      jazz: ['smooth', 'fusion', 'bebop', 'swing', 'contemporary'],
      electronic: ['house', 'techno', 'ambient', 'dubstep', 'trance'],
      'hip-hop': ['trap', 'boom-bap', 'conscious', 'mumble', 'old-school'],
      classical: ['baroque', 'romantic', 'contemporary', 'chamber'],
      country: ['modern', 'traditional', 'bluegrass', 'folk'],
      blues: ['electric', 'acoustic', 'chicago', 'delta'],
      reggae: ['roots', 'dancehall', 'dub', 'ska'],
      folk: ['indie', 'traditional', 'contemporary', 'acoustic'],
      metal: ['heavy', 'death', 'black', 'progressive', 'thrash'],
      punk: ['hardcore', 'pop-punk', 'post-punk', 'ska-punk'],
      indie: ['indie-rock', 'indie-folk', 'indie-electronic'],
      ambient: ['dark', 'drone', 'new-age', 'cinematic'],
      techno: ['minimal', 'acid', 'detroit', 'hard']
    }
    
    const options = subgenres[genre]
    return options ? vezaFaker.helpers.arrayElement(options) : undefined
  }

  private static generateTrackDescription(title: string, artist: string, genre: AudioGenre): string {
    const templates = [
      `Nouveau single de ${artist} - ${title}. Un morceau ${genre} qui ne vous laissera pas indifférent.`,
      `${title} par ${artist}. Une composition ${genre} originale et captivante.`,
      `Découvrez ${title}, le dernier titre de ${artist} dans un style ${genre} moderne.`,
      `${artist} nous présente ${title}, une pièce ${genre} pleine d'émotion.`,
      `${title} - Une création ${genre} signée ${artist}. À écouter absolument !`
    ]
    
    return vezaFaker.helpers.arrayElement(templates)
  }

  private static generateLyrics(): string {
    const verses = [
      "Dans la nuit étoilée, je marche seul\nMes pensées s'envolent vers l'horizon\nLa musique résonne dans mon cœur\nComme un écho de ma passion",
      
      "Les mélodies dansent dans l'air\nPortées par le vent du soir\nChaque note raconte une histoire\nD'amour, de joie et d'espoir",
      
      "Sur cette scène illuminée\nJe chante ma vérité\nLes mots s'échappent de mon âme\nPour toucher l'humanité"
    ]
    
    return vezaFaker.helpers.arrayElements(verses, vezaFaker.number.int({ min: 1, max: 3 })).join('\n\n')
  }

  private static generatePlaylistTitle(theme: string): string {
    const titles: Record<string, string[]> = {
      workout: ['Motivation Max', 'Energie Workout', 'Cardio Beats', 'Pump It Up', 'Training Zone'],
      chill: ['Détente Totale', 'Ambiance Chill', 'Relax Time', 'Zen Vibes', 'Sunday Morning'],
      party: ['Party Mix', 'Dancefloor Hits', 'Soirée Endiablée', 'Club Anthems', 'Weekend Vibes'],
      focus: ['Focus Mode', 'Concentration', 'Study Beats', 'Deep Work', 'Productivité'],
      random: ['Mix du Jour', 'Découvertes', 'Playlist Perso', 'Mes Favoris', 'Random Play']
    }
    
    const themeOptions = titles[theme] || titles.random
    return vezaFaker.helpers.arrayElement(themeOptions)
  }

  private static generatePlaylistDescription(title: string, theme: string): string {
    const descriptions: Record<string, string[]> = {
      workout: [
        'Playlist parfaite pour vos séances de sport et d\'entraînement.',
        'Des beats énergiques pour vous motiver pendant l\'effort.',
        'La bande sonore idéale pour vos sessions fitness.'
      ],
      chill: [
        'Musiques relaxantes pour se détendre et décompresser.',
        'Ambiance apaisante pour vos moments de repos.',
        'Sons doux pour accompagner vos instants de tranquillité.'
      ],
      party: [
        'Hits incontournables pour faire la fête toute la nuit.',
        'Morceaux dansants pour mettre l\'ambiance.',
        'La playlist ultime pour vos soirées entre amis.'
      ],
      focus: [
        'Musiques instrumentales pour améliorer votre concentration.',
        'Sons apaisants pour favoriser la productivité.',
        'Ambiance sonore idéale pour le travail et les études.'
      ],
      random: [
        'Sélection éclectique de mes morceaux préférés.',
        'Mix varié pour toutes les humeurs.',
        'Découvertes musicales et coups de cœur.'
      ]
    }
    
    const themeDescriptions = descriptions[theme] || descriptions.random
    return vezaFaker.helpers.arrayElement(themeDescriptions)
  }

  private static generatePlaylistTags(theme: string): string[] {
    const tags: Record<string, string[]> = {
      workout: ['sport', 'motivation', 'énergie', 'cardio', 'fitness'],
      chill: ['détente', 'relaxation', 'calme', 'zen', 'ambient'],
      party: ['fête', 'danse', 'club', 'soirée', 'hits'],
      focus: ['concentration', 'étude', 'travail', 'instrumental', 'productivité'],
      random: ['mix', 'varié', 'découverte', 'éclectique', 'personnel']
    }
    
    const themeTags = tags[theme] || tags.random
    return vezaFaker.helpers.arrayElements(themeTags, vezaFaker.number.int({ min: 2, max: 4 }))
  }

  /**
   * Utility methods
   */
  static getGeneratedTrack(id: string): Audio | undefined {
    return this.generatedTracks.get(id)
  }

  static getGeneratedAlbum(id: string): Album | undefined {
    return this.generatedAlbums.get(id)
  }

  static getGeneratedPlaylist(id: string): Playlist | undefined {
    return this.generatedPlaylists.get(id)
  }

  static getAllGeneratedTracks(): Audio[] {
    return Array.from(this.generatedTracks.values())
  }

  static getAllGeneratedAlbums(): Album[] {
    return Array.from(this.generatedAlbums.values())
  }

  static getAllGeneratedPlaylists(): Playlist[] {
    return Array.from(this.generatedPlaylists.values())
  }

  static clearCache(): void {
    this.generatedTracks.clear()
    this.generatedAlbums.clear()
    this.generatedPlaylists.clear()
    this.usedSlugs.clear()
  }

  static getStats(): {
    totalTracks: number
    totalAlbums: number
    totalPlaylists: number
    byGenre: Record<AudioGenre, number>
  } {
    const tracks = this.getAllGeneratedTracks()
    const byGenre: Record<AudioGenre, number> = {
      rock: 0, pop: 0, jazz: 0, classical: 0, electronic: 0, 'hip-hop': 0,
      country: 0, blues: 0, reggae: 0, folk: 0, metal: 0, punk: 0,
      indie: 0, ambient: 0, techno: 0
    }

    tracks.forEach(track => {
      byGenre[track.genre]++
    })

    return {
      totalTracks: tracks.length,
      totalAlbums: this.getAllGeneratedAlbums().length,
      totalPlaylists: this.getAllGeneratedPlaylists().length,
      byGenre
    }
  }
}