import type { ConversationHistory } from '../../types/conversation.js';
import type { StarsTransaction, CharacterAnalytics } from '../../types/api.js';

/**
 * Pure computation module for aggregating analytics data.
 * No I/O operations — all data is passed in as arguments.
 */
export class AnalyticsAggregator {
  /**
   * Aggregate conversation data into analytics.
   */
  aggregateConversations(conversations: ConversationHistory[]): CharacterAnalytics['conversations'] {
    let totalMessages = 0;
    const userIds = new Set<number>();
    let totalDuration = 0;
    let conversationsWithMessages = 0;

    for (const conv of conversations) {
      totalMessages += conv.messages.length;
      userIds.add(conv.telegramUserId);

      if (conv.messages.length >= 2) {
        const first = new Date(conv.messages[0].timestamp).getTime();
        const last = new Date(conv.messages[conv.messages.length - 1].timestamp).getTime();
        const durationMinutes = (last - first) / (1000 * 60);
        totalDuration += durationMinutes;
        conversationsWithMessages++;
      }
    }

    const uniqueUsers = userIds.size;
    const averageConversationDuration = conversationsWithMessages > 0
      ? Math.round((totalDuration / conversationsWithMessages) * 100) / 100
      : 0;
    const averageMessagesPerConversation = conversations.length > 0
      ? Math.round((totalMessages / conversations.length) * 100) / 100
      : 0;

    return {
      totalMessages,
      uniqueUsers,
      averageConversationDuration,
      averageMessagesPerConversation,
    };
  }

  /**
   * Aggregate Stars transactions into sales analytics.
   */
  aggregateSales(
    transactions: StarsTransaction[],
    conversations: ConversationHistory[],
  ): CharacterAnalytics['sales'] {
    const completedTx = transactions.filter(tx => tx.status === 'completed');
    const totalStarsEarned = completedTx.reduce((sum, tx) => sum + tx.starCount, 0);
    const totalTransactions = completedTx.length;

    // Count pitches and acceptances from conversation metadata
    let pitchCount = 0;
    let acceptCount = 0;
    for (const conv of conversations) {
      for (const msg of conv.messages) {
        if (msg.metadata?.starsPitchMade) pitchCount++;
        if (msg.metadata?.starsAccepted) acceptCount++;
      }
    }
    const conversionRate = pitchCount > 0
      ? Math.round((acceptCount / pitchCount) * 10000) / 10000
      : 0;

    // Average stars per unique user
    const payingUsers = new Set(completedTx.map(tx => tx.telegramUserId));
    const averageStarsPerUser = payingUsers.size > 0
      ? Math.round((totalStarsEarned / payingUsers.size) * 100) / 100
      : 0;

    // Top selling hours
    const hourlyStars: Record<number, number> = {};
    for (let h = 0; h < 24; h++) hourlyStars[h] = 0;
    for (const tx of completedTx) {
      const hour = new Date(tx.createdAt).getUTCHours();
      hourlyStars[hour] = (hourlyStars[hour] || 0) + tx.starCount;
    }
    const topSellingHours = Object.entries(hourlyStars)
      .sort((a, b) => b[1] - a[1])
      .filter(([, count]) => count > 0)
      .slice(0, 3)
      .map(([hour]) => Number(hour));

    return {
      totalStarsEarned,
      totalTransactions,
      conversionRate,
      averageStarsPerUser,
      topSellingHours,
    };
  }

  /**
   * Aggregate activity patterns from conversations and transactions.
   */
  aggregateActivity(
    conversations: ConversationHistory[],
    transactions: StarsTransaction[],
  ): CharacterAnalytics['activity'] {
    const hourlyMessageCount: Record<number, number> = {};
    const hourlyStarsCount: Record<number, number> = {};
    for (let h = 0; h < 24; h++) {
      hourlyMessageCount[h] = 0;
      hourlyStarsCount[h] = 0;
    }

    for (const conv of conversations) {
      for (const msg of conv.messages) {
        const hour = new Date(msg.timestamp).getUTCHours();
        hourlyMessageCount[hour] = (hourlyMessageCount[hour] || 0) + 1;
      }
    }

    const completedTx = transactions.filter(tx => tx.status === 'completed');
    for (const tx of completedTx) {
      const hour = new Date(tx.createdAt).getUTCHours();
      hourlyStarsCount[hour] = (hourlyStarsCount[hour] || 0) + tx.starCount;
    }

    let peakHour = 0;
    let quietHour = 0;
    let maxMessages = -1;
    let minMessages = Infinity;

    for (let h = 0; h < 24; h++) {
      if (hourlyMessageCount[h] > maxMessages) {
        maxMessages = hourlyMessageCount[h];
        peakHour = h;
      }
      if (hourlyMessageCount[h] < minMessages) {
        minMessages = hourlyMessageCount[h];
        quietHour = h;
      }
    }

    return {
      hourlyMessageCount,
      hourlyStarsCount,
      peakHour,
      quietHour,
    };
  }
}
