/**
 * Live Streaming System
 * Integration with Twitch and YouTube for tournaments and player broadcasts
 */

export type StreamPlatform = 'twitch' | 'youtube' | 'both';
export type StreamStatus = 'offline' | 'live' | 'scheduled' | 'ended';
export type StreamType = 'tournament' | 'gameplay' | 'community' | 'coaching';

export interface LiveStream {
  id: string;
  userId: number;
  username: string;
  title: string;
  description: string;
  platform: StreamPlatform;
  streamUrl: string;
  thumbnailUrl?: string;
  status: StreamStatus;
  type: StreamType;
  viewers: number;
  startTime: Date;
  endTime?: Date;
  duration?: number; // seconds
  tags: string[];
  category: string;
  isMonetized: boolean;
  earnings: number;
}

export interface StreamSettings {
  platform: StreamPlatform;
  twitchChannelId?: string;
  twitchOAuthToken?: string;
  youtubeChannelId?: string;
  youtubeOAuthToken?: string;
  autoStartStream: boolean;
  autoEndStream: boolean;
  chatEnabled: boolean;
  donationsEnabled: boolean;
  recordStream: boolean;
}

export interface StreamViewerMetrics {
  streamId: string;
  totalViewers: number;
  peakViewers: number;
  averageViewDuration: number; // seconds
  uniqueViewers: number;
  chatMessages: number;
  donations: number;
  donationAmount: number;
}

export interface StreamDonation {
  id: string;
  streamId: string;
  donorId: number;
  donorUsername: string;
  amount: number;
  currency: string;
  message: string;
  timestamp: Date;
  platform: 'twitch' | 'youtube' | 'direct';
}

export interface StreamChat {
  id: string;
  streamId: string;
  userId: number;
  username: string;
  message: string;
  timestamp: Date;
  platform: 'twitch' | 'youtube';
  isModerator: boolean;
  isStreamer: boolean;
}

export interface TournamentStream {
  id: string;
  tournamentId: string;
  tournamentName: string;
  streamId: string;
  streamerUserId: number;
  streamerUsername: string;
  platform: StreamPlatform;
  status: StreamStatus;
  startTime: Date;
  endTime?: Date;
  viewers: number;
  totalDonations: number;
  featuredPlayers: number[];
}

/**
 * Create live stream
 */
export function createLiveStream(
  userId: number,
  username: string,
  title: string,
  description: string,
  platform: StreamPlatform,
  type: StreamType,
  category: string
): LiveStream {
  return {
    id: `stream_${userId}_${Date.now()}`,
    userId,
    username,
    title,
    description,
    platform,
    streamUrl: `https://${platform}.com/${username}/live`,
    status: 'scheduled',
    type,
    viewers: 0,
    startTime: new Date(),
    tags: [],
    category,
    isMonetized: false,
    earnings: 0,
  };
}

/**
 * Start live stream
 */
export function startLiveStream(stream: LiveStream): void {
  stream.status = 'live';
  stream.startTime = new Date();
  stream.viewers = 0;
}

/**
 * End live stream
 */
export function endLiveStream(stream: LiveStream): void {
  stream.status = 'ended';
  stream.endTime = new Date();
  stream.duration = Math.floor((stream.endTime.getTime() - stream.startTime.getTime()) / 1000);
}

/**
 * Update viewer count
 */
export function updateViewerCount(stream: LiveStream, count: number): void {
  stream.viewers = count;
}

/**
 * Add donation to stream
 */
export function addStreamDonation(
  stream: LiveStream,
  donorId: number,
  donorUsername: string,
  amount: number,
  currency: string,
  message: string,
  platform: 'twitch' | 'youtube' | 'direct'
): StreamDonation {
  const donation: StreamDonation = {
    id: `donation_${stream.id}_${Date.now()}`,
    streamId: stream.id,
    donorId,
    donorUsername,
    amount,
    currency,
    message,
    timestamp: new Date(),
    platform,
  };

  stream.earnings += amount;
  return donation;
}

/**
 * Add chat message to stream
 */
export function addStreamChatMessage(
  stream: LiveStream,
  userId: number,
  username: string,
  message: string,
  platform: 'twitch' | 'youtube',
  isModerator: boolean = false
): StreamChat {
  return {
    id: `chat_${stream.id}_${userId}_${Date.now()}`,
    streamId: stream.id,
    userId,
    username,
    message,
    timestamp: new Date(),
    platform,
    isModerator,
    isStreamer: userId === stream.userId,
  };
}

/**
 * Calculate stream viewer metrics
 */
export function calculateStreamMetrics(
  stream: LiveStream,
  donations: StreamDonation[],
  chatMessages: StreamChat[],
  viewerSessions: Array<{ userId: number; joinTime: Date; leaveTime?: Date }>
): StreamViewerMetrics {
  const uniqueViewers = new Set(viewerSessions.map((v) => v.userId)).size;

  const viewDurations = viewerSessions.map((v) => {
    const leaveTime = v.leaveTime || new Date();
    return (leaveTime.getTime() - v.joinTime.getTime()) / 1000;
  });

  const averageViewDuration = viewDurations.length > 0
    ? viewDurations.reduce((a, b) => a + b, 0) / viewDurations.length
    : 0;

  const streamDonations = donations.filter((d) => d.streamId === stream.id);
  const donationAmount = streamDonations.reduce((sum, d) => sum + d.amount, 0);

  return {
    streamId: stream.id,
    totalViewers: stream.viewers,
    peakViewers: stream.viewers,
    averageViewDuration,
    uniqueViewers,
    chatMessages: chatMessages.filter((c) => c.streamId === stream.id).length,
    donations: streamDonations.length,
    donationAmount,
  };
}

/**
 * Create tournament stream
 */
export function createTournamentStream(
  tournamentId: string,
  tournamentName: string,
  streamerUserId: number,
  streamerUsername: string,
  platform: StreamPlatform
): TournamentStream {
  return {
    id: `tstream_${tournamentId}_${Date.now()}`,
    tournamentId,
    tournamentName,
    streamId: `stream_${streamerUserId}_${Date.now()}`,
    streamerUserId,
    streamerUsername,
    platform,
    status: 'scheduled',
    startTime: new Date(),
    viewers: 0,
    totalDonations: 0,
    featuredPlayers: [],
  };
}

/**
 * Add featured player to tournament stream
 */
export function addFeaturedPlayerToStream(stream: TournamentStream, playerId: number): void {
  if (!stream.featuredPlayers.includes(playerId)) {
    stream.featuredPlayers.push(playerId);
  }
}

/**
 * Remove featured player from tournament stream
 */
export function removeFeaturedPlayerFromStream(stream: TournamentStream, playerId: number): void {
  const index = stream.featuredPlayers.indexOf(playerId);
  if (index !== -1) {
    stream.featuredPlayers.splice(index, 1);
  }
}

/**
 * Stream monetization configuration
 */
export interface StreamMonetization {
  enabled: boolean;
  donationPercentage: number; // Platform takes this percentage
  minimumDonation: number;
  currency: string;
  payoutMethod: 'bank_transfer' | 'paypal' | 'crypto';
  payoutThreshold: number;
}

/**
 * Stream analytics
 */
export interface StreamAnalytics {
  streamId: string;
  totalViewTime: number; // hours
  averageViewersPerMinute: number;
  engagementRate: number; // % of viewers who chatted
  donationConversionRate: number; // % of viewers who donated
  topDonors: Array<{ username: string; totalDonated: number }>;
  topChatters: Array<{ username: string; messageCount: number }>;
}

export function calculateStreamAnalytics(
  stream: LiveStream,
  metrics: StreamViewerMetrics,
  donations: StreamDonation[],
  chatMessages: StreamChat[]
): StreamAnalytics {
  const streamDonations = donations.filter((d) => d.streamId === stream.id);
  const streamChat = chatMessages.filter((c) => c.streamId === stream.id);

  const totalViewTime = stream.duration ? stream.duration / 3600 : 0;
  const averageViewersPerMinute = stream.duration ? metrics.totalViewers / (stream.duration / 60) : 0;
  const engagementRate = metrics.uniqueViewers > 0
    ? (new Set(streamChat.map((c) => c.userId)).size / metrics.uniqueViewers) * 100
    : 0;
  const donationConversionRate = metrics.uniqueViewers > 0
    ? (new Set(streamDonations.map((d) => d.donorId)).size / metrics.uniqueViewers) * 100
    : 0;

  // Top donors
  const donorMap: Record<string, number> = {};
  streamDonations.forEach((d) => {
    donorMap[d.donorUsername] = (donorMap[d.donorUsername] || 0) + d.amount;
  });

  const topDonors = Object.entries(donorMap)
    .map(([username, totalDonated]) => ({ username, totalDonated }))
    .sort((a, b) => b.totalDonated - a.totalDonated)
    .slice(0, 10);

  // Top chatters
  const chatterMap: Record<string, number> = {};
  streamChat.forEach((c) => {
    chatterMap[c.username] = (chatterMap[c.username] || 0) + 1;
  });

  const topChatters = Object.entries(chatterMap)
    .map(([username, messageCount]) => ({ username, messageCount }))
    .sort((a, b) => b.messageCount - a.messageCount)
    .slice(0, 10);

  return {
    streamId: stream.id,
    totalViewTime,
    averageViewersPerMinute,
    engagementRate,
    donationConversionRate,
    topDonors,
    topChatters,
  };
}

/**
 * Stream scheduling
 */
export interface ScheduledStream {
  id: string;
  userId: number;
  username: string;
  title: string;
  scheduledStartTime: Date;
  platform: StreamPlatform;
  notifyFollowers: boolean;
  createdAt: Date;
}

export function createScheduledStream(
  userId: number,
  username: string,
  title: string,
  scheduledStartTime: Date,
  platform: StreamPlatform
): ScheduledStream {
  return {
    id: `sched_${userId}_${Date.now()}`,
    userId,
    username,
    title,
    scheduledStartTime,
    platform,
    notifyFollowers: true,
    createdAt: new Date(),
  };
}

/**
 * Get upcoming streams
 */
export function getUpcomingStreams(
  streams: ScheduledStream[],
  hoursAhead: number = 24
): ScheduledStream[] {
  const now = new Date();
  const futureTime = new Date(now.getTime() + hoursAhead * 60 * 60 * 1000);

  return streams
    .filter((s) => s.scheduledStartTime > now && s.scheduledStartTime < futureTime)
    .sort((a, b) => a.scheduledStartTime.getTime() - b.scheduledStartTime.getTime());
}

/**
 * Stream recommendations
 */
export interface StreamRecommendation {
  streamId: string;
  title: string;
  username: string;
  viewers: number;
  category: string;
  platform: StreamPlatform;
  score: number; // Recommendation score 0-100
}

export function getStreamRecommendations(
  streams: LiveStream[],
  userPreferences: { categories: string[]; platforms: StreamPlatform[] }
): StreamRecommendation[] {
  return streams
    .filter(
      (s) =>
        s.status === 'live' &&
        userPreferences.platforms.includes(s.platform) &&
        userPreferences.categories.includes(s.category)
    )
    .map((s) => ({
      streamId: s.id,
      title: s.title,
      username: s.username,
      viewers: s.viewers,
      category: s.category,
      platform: s.platform,
      score: Math.min(100, (s.viewers / 1000) * 50 + 50), // Score based on viewers
    }))
    .sort((a, b) => b.score - a.score)
    .slice(0, 10);
}
