import { EventEmitter } from 'events';

interface StreamSession {
  id: string;
  userId: string;
  platform: 'twitch' | 'youtube';
  streamKey: string;
  title: string;
  description: string;
  isLive: boolean;
  viewers: number;
  startTime: Date;
  endTime?: Date;
  gameId: string;
  recordingUrl?: string;
  stats: {
    totalViews: number;
    peakViewers: number;
    averageViewTime: number;
    donations: number;
  };
}

interface StreamDonation {
  id: string;
  streamId: string;
  donorId: string;
  amount: number;
  message: string;
  timestamp: Date;
}

interface StreamRecording {
  id: string;
  streamId: string;
  url: string;
  duration: number;
  fileSize: number;
  quality: '720p' | '1080p' | '4k';
  createdAt: Date;
}

export class GameStreamingSystem extends EventEmitter {
  private streams = new Map<string, StreamSession>();
  private donations = new Map<string, StreamDonation[]>();
  private recordings = new Map<string, StreamRecording[]>();

  /**
   * Start a new stream session
   */
  startStream(userId: string, config: {
    platform: 'twitch' | 'youtube';
    title: string;
    description: string;
    gameId: string;
  }): StreamSession {
    const streamId = `stream_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    const streamKey = this.generateStreamKey();

    const session: StreamSession = {
      id: streamId,
      userId,
      platform: config.platform,
      streamKey,
      title: config.title,
      description: config.description,
      isLive: true,
      viewers: 0,
      startTime: new Date(),
      gameId: config.gameId,
      stats: {
        totalViews: 0,
        peakViewers: 0,
        averageViewTime: 0,
        donations: 0,
      },
    };

    this.streams.set(streamId, session);
    this.donations.set(streamId, []);
    this.recordings.set(streamId, []);

    this.emit('stream:started', { streamId, userId, platform: config.platform });

    return session;
  }

  /**
   * End a stream session
   */
  endStream(streamId: string): StreamSession | null {
    const stream = this.streams.get(streamId);
    if (!stream) return null;

    stream.isLive = false;
    stream.endTime = new Date();

    this.emit('stream:ended', { streamId, userId: stream.userId });

    return stream;
  }

  /**
   * Update viewer count
   */
  updateViewerCount(streamId: string, viewerCount: number): void {
    const stream = this.streams.get(streamId);
    if (!stream) return;

    stream.viewers = viewerCount;
    stream.stats.totalViews += viewerCount;

    if (viewerCount > stream.stats.peakViewers) {
      stream.stats.peakViewers = viewerCount;
    }

    this.emit('stream:viewers-updated', { streamId, viewers: viewerCount });
  }

  /**
   * Record a donation during stream
   */
  recordDonation(streamId: string, donation: {
    donorId: string;
    amount: number;
    message: string;
  }): StreamDonation {
    const stream = this.streams.get(streamId);
    if (!stream) throw new Error('Stream not found');

    const donationRecord: StreamDonation = {
      id: `donation_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      streamId,
      donorId: donation.donorId,
      amount: donation.amount,
      message: donation.message,
      timestamp: new Date(),
    };

    const streamDonations = this.donations.get(streamId) || [];
    streamDonations.push(donationRecord);
    this.donations.set(streamId, streamDonations);

    stream.stats.donations += donation.amount;

    this.emit('stream:donation', {
      streamId,
      donation: donationRecord,
      totalDonations: stream.stats.donations,
    });

    return donationRecord;
  }

  /**
   * Get stream details
   */
  getStream(streamId: string): StreamSession | null {
    return this.streams.get(streamId) || null;
  }

  /**
   * Get active streams
   */
  getActiveStreams(userId?: string): StreamSession[] {
    const active = Array.from(this.streams.values()).filter(s => s.isLive);
    return userId ? active.filter(s => s.userId === userId) : active;
  }

  /**
   * Get stream donations
   */
  getStreamDonations(streamId: string): StreamDonation[] {
    return this.donations.get(streamId) || [];
  }

  /**
   * Create stream recording
   */
  createRecording(streamId: string, recordingData: {
    url: string;
    duration: number;
    fileSize: number;
    quality: '720p' | '1080p' | '4k';
  }): StreamRecording {
    const recording: StreamRecording = {
      id: `recording_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      streamId,
      url: recordingData.url,
      duration: recordingData.duration,
      fileSize: recordingData.fileSize,
      quality: recordingData.quality,
      createdAt: new Date(),
    };

    const streamRecordings = this.recordings.get(streamId) || [];
    streamRecordings.push(recording);
    this.recordings.set(streamId, streamRecordings);

    this.emit('stream:recording-created', { streamId, recording });

    return recording;
  }

  /**
   * Get stream recordings
   */
  getRecordings(streamId: string): StreamRecording[] {
    return this.recordings.get(streamId) || [];
  }

  /**
   * Get stream analytics
   */
  getStreamAnalytics(streamId: string) {
    const stream = this.streams.get(streamId);
    if (!stream) return null;

    const donations = this.donations.get(streamId) || [];
    const recordings = this.recordings.get(streamId) || [];

    return {
      stream,
      donations,
      recordings,
      summary: {
        totalViewers: stream.stats.totalViews,
        peakViewers: stream.stats.peakViewers,
        totalDonations: stream.stats.donations,
        donationCount: donations.length,
        recordingCount: recordings.length,
        duration: stream.endTime
          ? (stream.endTime.getTime() - stream.startTime.getTime()) / 1000
          : (Date.now() - stream.startTime.getTime()) / 1000,
      },
    };
  }

  /**
   * Generate unique stream key
   */
  private generateStreamKey(): string {
    return `${Math.random().toString(36).substr(2, 16)}_${Date.now()}`;
  }

  /**
   * Get top streamers
   */
  getTopStreamers(limit: number = 10) {
    return Array.from(this.streams.values())
      .filter(s => s.isLive)
      .sort((a, b) => b.viewers - a.viewers)
      .slice(0, limit)
      .map(s => ({
        streamId: s.id,
        userId: s.userId,
        title: s.title,
        viewers: s.viewers,
        platform: s.platform,
        gameId: s.gameId,
      }));
  }

  /**
   * Get stream recommendations
   */
  getStreamRecommendations(userId: string, limit: number = 5) {
    return Array.from(this.streams.values())
      .filter(s => s.isLive && s.userId !== userId)
      .sort((a, b) => b.viewers - a.viewers)
      .slice(0, limit)
      .map(s => ({
        streamId: s.id,
        userId: s.userId,
        title: s.title,
        viewers: s.viewers,
        platform: s.platform,
        gameId: s.gameId,
      }));
  }
}

export const gameStreamingSystem = new GameStreamingSystem();
