import { creditWallet, writeAuditLog } from './db.ts';

export interface StreamerProfile {
  id: string;
  userId: number;
  username: string;
  displayName: string;
  bio?: string;
  avatar?: string;
  twitchHandle?: string;
  youtubeHandle?: string;
  discordHandle?: string;
  affiliateCode: string;
  affiliateCommissionRate: number; // 5-15%
  isVerified: boolean;
  totalReferrals: number;
  totalEarnings: number;
  monthlyEarnings: number;
  viewerCount: number;
  followerCount: number;
  createdAt: Date;
  updatedAt: Date;
}

export interface StreamSession {
  id: string;
  streamerId: number;
  title: string;
  description?: string;
  platform: 'twitch' | 'youtube' | 'other';
  streamUrl?: string;
  startTime: Date;
  endTime?: Date;
  viewerCount: number;
  peakViewers: number;
  duration: number; // minutes
  engagement: number; // 0-100
}

export interface StreamerEarnings {
  streamerId: number;
  date: Date;
  referralEarnings: number;
  hostingBonusEarnings: number;
  challengeEarnings: number;
  totalEarnings: number;
}

/**
 * Streamer Integration Manager
 */
export class StreamerIntegrationManager {
  private streamers: Map<number, StreamerProfile> = new Map();
  private sessions: Map<string, StreamSession> = new Map();
  private earnings: Map<string, StreamerEarnings> = new Map();
  private affiliateCodes: Map<string, number> = new Map(); // code -> userId

  /**
   * Register streamer
   */
  async registerStreamer(
    userId: number,
    username: string,
    displayName: string
  ): Promise<StreamerProfile> {
    const affiliateCode = this.generateAffiliateCode();

    const profile: StreamerProfile = {
      id: `streamer_${userId}`,
      userId,
      username,
      displayName,
      affiliateCode,
      affiliateCommissionRate: 5, // Start at 5%
      isVerified: false,
      totalReferrals: 0,
      totalEarnings: 0,
      monthlyEarnings: 0,
      viewerCount: 0,
      followerCount: 0,
      createdAt: new Date(),
      updatedAt: new Date(),
    };

    this.streamers.set(userId, profile);
    this.affiliateCodes.set(affiliateCode, userId);

    await writeAuditLog({
      actorId: userId,
      actorRole: 'user',
      action: 'streamer_registered',
      category: 'streamer',
      details: { username, affiliateCode },
    });

    return profile;
  }

  /**
   * Generate unique affiliate code
   */
  private generateAffiliateCode(): string {
    let code = '';
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

    for (let i = 0; i < 8; i++) {
      code += chars.charAt(Math.floor(Math.random() * chars.length));
    }

    // Ensure uniqueness
    if (this.affiliateCodes.has(code)) {
      return this.generateAffiliateCode();
    }

    return code;
  }

  /**
   * Get streamer profile
   */
  async getStreamerProfile(userId: number): Promise<StreamerProfile | null> {
    return this.streamers.get(userId) || null;
  }

  /**
   * Update streamer profile
   */
  async updateStreamerProfile(userId: number, updates: Partial<StreamerProfile>): Promise<StreamerProfile | null> {
    const profile = this.streamers.get(userId);
    if (!profile) return null;

    Object.assign(profile, updates, { updatedAt: new Date() });

    await writeAuditLog({
      actorId: userId,
      actorRole: 'user',
      action: 'streamer_profile_updated',
      category: 'streamer',
      details: updates,
    });

    return profile;
  }

  /**
   * Verify streamer
   */
  async verifyStreamer(userId: number): Promise<void> {
    const profile = this.streamers.get(userId);
    if (profile) {
      profile.isVerified = true;
      profile.affiliateCommissionRate = Math.min(profile.affiliateCommissionRate + 2, 15); // Increase to max 15%

      await writeAuditLog({
        actorId: userId,
        actorRole: 'admin',
        action: 'streamer_verified',
        category: 'streamer',
        details: { newCommissionRate: profile.affiliateCommissionRate },
      });
    }
  }

  /**
   * Start stream session
   */
  async startStreamSession(
    streamerId: number,
    title: string,
    platform: 'twitch' | 'youtube' | 'other',
    streamUrl?: string,
    description?: string
  ): Promise<StreamSession> {
    const session: StreamSession = {
      id: `session_${Date.now()}_${Math.random().toString(36).substring(7)}`,
      streamerId,
      title,
      description,
      platform,
      streamUrl,
      startTime: new Date(),
      viewerCount: 0,
      peakViewers: 0,
      duration: 0,
      engagement: 0,
    };

    this.sessions.set(session.id, session);

    await writeAuditLog({
      actorId: streamerId,
      actorRole: 'user',
      action: 'stream_session_started',
      category: 'streamer',
      details: { title, platform },
    });

    return session;
  }

  /**
   * Update stream session stats
   */
  async updateStreamStats(sessionId: string, viewerCount: number, engagement: number): Promise<void> {
    const session = this.sessions.get(sessionId);
    if (session) {
      session.viewerCount = viewerCount;
      session.peakViewers = Math.max(session.peakViewers, viewerCount);
      session.engagement = Math.min(engagement, 100);
    }
  }

  /**
   * End stream session
   */
  async endStreamSession(sessionId: string): Promise<StreamSession | null> {
    const session = this.sessions.get(sessionId);
    if (!session) return null;

    session.endTime = new Date();
    session.duration = Math.floor((session.endTime.getTime() - session.startTime.getTime()) / 60000);

    // Calculate hosting bonus based on engagement and duration
    const hostingBonus = Math.floor((session.peakViewers * session.engagement * session.duration) / 1000);

    // Award bonus to streamer
    if (hostingBonus > 0) {
      const profile = this.streamers.get(session.streamerId);
      if (profile) {
        await creditWallet(
          session.streamerId,
          'SC',
          hostingBonus,
          'hosting_bonus',
          `Hosting bonus for stream: ${session.title}`,
          String(session.streamerId)
        );

        profile.totalEarnings += hostingBonus;
        profile.monthlyEarnings += hostingBonus;
      }
    }

    await writeAuditLog({
      actorId: session.streamerId,
      actorRole: 'user',
      action: 'stream_session_ended',
      category: 'streamer',
      details: { duration: session.duration, hostingBonus },
    });

    return session;
  }

  /**
   * Record referral conversion
   */
  async recordReferralConversion(affiliateCode: string, newUserId: number, firstWagerAmount: number): Promise<void> {
    const streamerId = this.affiliateCodes.get(affiliateCode);
    if (!streamerId) return;

    const profile = this.streamers.get(streamerId);
    if (!profile) return;

    // Calculate commission (5-15% of first wager)
    const commission = Math.floor(firstWagerAmount * (profile.affiliateCommissionRate / 100));

    // Award commission
    await creditWallet(
      streamerId,
      'SC',
      commission,
      'referral_commission',
      `Referral commission from user ${newUserId}`,
      String(streamerId)
    );

    profile.totalReferrals++;
    profile.totalEarnings += commission;
    profile.monthlyEarnings += commission;

    await writeAuditLog({
      actorId: streamerId,
      actorRole: 'system',
      action: 'referral_conversion',
      category: 'streamer',
      details: { newUserId, commission, firstWagerAmount },
    });
  }

  /**
   * Get streamer earnings
   */
  async getStreamerEarnings(streamerId: number, month?: Date): Promise<StreamerEarnings | null> {
    const date = month || new Date();
    const dateKey = `${streamerId}_${date.getFullYear()}_${date.getMonth()}`;

    let earnings = this.earnings.get(dateKey);
    if (!earnings) {
      earnings = {
        streamerId,
        date,
        referralEarnings: 0,
        hostingBonusEarnings: 0,
        challengeEarnings: 0,
        totalEarnings: 0,
      };
      this.earnings.set(dateKey, earnings);
    }

    return earnings;
  }

  /**
   * Get top streamers
   */
  async getTopStreamers(limit: number = 10): Promise<Array<{
    rank: number;
    displayName: string;
    totalEarnings: number;
    totalReferrals: number;
    isVerified: boolean;
  }>> {
    const sorted = Array.from(this.streamers.values())
      .sort((a, b) => b.totalEarnings - a.totalEarnings)
      .slice(0, limit);

    return sorted.map((s, index) => ({
      rank: index + 1,
      displayName: s.displayName,
      totalEarnings: s.totalEarnings,
      totalReferrals: s.totalReferrals,
      isVerified: s.isVerified,
    }));
  }

  /**
   * Get streamer dashboard data
   */
  async getStreamerDashboard(streamerId: number): Promise<{
    profile: StreamerProfile | null;
    monthlyEarnings: number;
    totalReferrals: number;
    recentSessions: StreamSession[];
    topPerformingSession?: StreamSession;
    rank: number;
  } | null> {
    const profile = this.streamers.get(streamerId);
    if (!profile) return null;

    const recentSessions = Array.from(this.sessions.values())
      .filter((s) => s.streamerId === streamerId)
      .sort((a, b) => b.startTime.getTime() - a.startTime.getTime())
      .slice(0, 10);

    const topPerformingSession = recentSessions.reduce((top, session) => {
      if (!top || session.peakViewers > top.peakViewers) {
        return session;
      }
      return top;
    }, recentSessions[0]);

    // Calculate rank
    const allStreamers = Array.from(this.streamers.values()).sort((a, b) => b.totalEarnings - a.totalEarnings);
    const rank = allStreamers.findIndex((s) => s.userId === streamerId) + 1;

    return {
      profile,
      monthlyEarnings: profile.monthlyEarnings,
      totalReferrals: profile.totalReferrals,
      recentSessions,
      topPerformingSession,
      rank,
    };
  }

  /**
   * Get streamer stats
   */
  async getStats(): Promise<{
    totalStreamers: number;
    verifiedStreamers: number;
    totalEarningsDistributed: number;
    totalReferrals: number;
    averageEarningsPerStreamer: number;
  }> {
    let totalEarnings = 0;
    let totalReferrals = 0;
    let verifiedCount = 0;

    for (const streamer of this.streamers.values()) {
      totalEarnings += streamer.totalEarnings;
      totalReferrals += streamer.totalReferrals;
      if (streamer.isVerified) {
        verifiedCount++;
      }
    }

    return {
      totalStreamers: this.streamers.size,
      verifiedStreamers: verifiedCount,
      totalEarningsDistributed: totalEarnings,
      totalReferrals,
      averageEarningsPerStreamer: this.streamers.size > 0 ? totalEarnings / this.streamers.size : 0,
    };
  }
}

export const streamerIntegrationManager = new StreamerIntegrationManager();
