/**
 * Query: GetUserRatingsSummaryQuery
 * 
 * Fast read query for user rating summary.
 * Combines platform snapshots and external game ratings.
 */

import { ExternalGameRatingRepository } from '../../domain/repositories/ExternalGameRatingRepository';
import { RatingEventRepository } from '../../domain/repositories/RatingEventRepository';
import { UserRatingRepository } from '../../domain/repositories/UserRatingRepository';
import { RatingSummaryDto } from '../dtos/RatingSummaryDto';

export interface GetUserRatingsSummaryQuery {
  userId: string;
}

export class GetUserRatingsSummaryQueryHandler {
  constructor(
    private readonly userRatingRepo: UserRatingRepository,
    private readonly externalRatingRepo: ExternalGameRatingRepository,
    private readonly ratingEventRepo: RatingEventRepository
  ) {}

  async execute(query: GetUserRatingsSummaryQuery): Promise<RatingSummaryDto> {
    const { userId } = query;

    // Fetch platform rating snapshot
    const userRating = await this.userRatingRepo.findByUserId(userId);
    
    // Fetch all external game ratings
    const externalProfiles = await this.externalRatingRepo.findByUserId(userId);

    // Get last event timestamp if available
    let lastRatingEventAt: string | undefined;
    if (userRating) {
      // Get all events to find the most recent one
      const events = await this.ratingEventRepo.getAllByUserId(userId);
      if (events.length > 0) {
        const lastEvent = events[events.length - 1];
        if (lastEvent) {
          lastRatingEventAt = lastEvent.occurredAt.toISOString();
        }
      }
    }

    // Build platform rating dimensions
    const platform = {
      driving: {
        value: userRating?.driver.value || 0,
        confidence: userRating?.driver.confidence || 0,
        sampleSize: userRating?.driver.sampleSize || 0,
        trend: userRating?.driver.trend || 'stable',
        lastUpdated: userRating?.driver.lastUpdated?.toISOString() || new Date(0).toISOString(),
      },
      admin: {
        value: userRating?.admin.value || 0,
        confidence: userRating?.admin.confidence || 0,
        sampleSize: userRating?.admin.sampleSize || 0,
        trend: userRating?.admin.trend || 'stable',
        lastUpdated: userRating?.admin.lastUpdated?.toISOString() || new Date(0).toISOString(),
      },
      steward: {
        value: userRating?.steward.value || 0,
        confidence: userRating?.steward.confidence || 0,
        sampleSize: userRating?.steward.sampleSize || 0,
        trend: userRating?.steward.trend || 'stable',
        lastUpdated: userRating?.steward.lastUpdated?.toISOString() || new Date(0).toISOString(),
      },
      trust: {
        value: userRating?.trust.value || 0,
        confidence: userRating?.trust.confidence || 0,
        sampleSize: userRating?.trust.sampleSize || 0,
        trend: userRating?.trust.trend || 'stable',
        lastUpdated: userRating?.trust.lastUpdated?.toISOString() || new Date(0).toISOString(),
      },
      fairness: {
        value: userRating?.fairness.value || 0,
        confidence: userRating?.fairness.confidence || 0,
        sampleSize: userRating?.fairness.sampleSize || 0,
        trend: userRating?.fairness.trend || 'stable',
        lastUpdated: userRating?.fairness.lastUpdated?.toISOString() || new Date(0).toISOString(),
      },
      overallReputation: userRating?.overallReputation || 0,
    };

    // Build external ratings map
    const external: { [gameKey: string]: { [type: string]: number } } = {};
    
    for (const profile of externalProfiles) {
      const gameKey = profile.gameKey.toString();
      external[gameKey] = {};
      
      // Convert Map to array and iterate
      const ratingsArray = Array.from(profile.ratings.entries());
      for (const [type, rating] of ratingsArray) {
        external[gameKey][type] = rating.value;
      }
    }

    // Get timestamps
    const createdAt = userRating?.createdAt?.toISOString() || new Date().toISOString();
    const updatedAt = userRating?.updatedAt?.toISOString() || new Date().toISOString();

    const result: RatingSummaryDto = {
      userId,
      platform,
      external,
      createdAt,
      updatedAt,
    };

    if (lastRatingEventAt) {
      result.lastRatingEventAt = lastRatingEventAt;
    }

    return result;
  }
}
