/**
 * Query: GetUserRatingLedgerQuery
 * 
 * Paginated/filtered query for user rating events (ledger).
 */

import { PaginatedQueryOptions, RatingEventFilter, RatingEventRepository } from '../../domain/repositories/RatingEventRepository';
import { LedgerEntryDto, LedgerFilter, PaginatedLedgerResult } from '../dtos/LedgerEntryDto';

export interface GetUserRatingLedgerQuery {
  userId: string;
  limit?: number;
  offset?: number;
  filter?: LedgerFilter;
}

export class GetUserRatingLedgerQueryHandler {
  constructor(
    private readonly ratingEventRepo: RatingEventRepository
  ) {}

  async execute(query: GetUserRatingLedgerQuery): Promise<PaginatedLedgerResult> {
    const { userId, limit = 20, offset = 0, filter } = query;

    // Build repo options
    const repoOptions: PaginatedQueryOptions = {
      limit,
      offset,
    };

    // Add filter if provided
    if (filter) {
      const ratingEventFilter: RatingEventFilter = {};
      
      if (filter.dimensions) {
        ratingEventFilter.dimensions = filter.dimensions;
      }
      if (filter.sourceTypes) {
        ratingEventFilter.sourceTypes = filter.sourceTypes;
      }
      if (filter.from) {
        ratingEventFilter.from = new Date(filter.from);
      }
      if (filter.to) {
        ratingEventFilter.to = new Date(filter.to);
      }
      if (filter.reasonCodes) {
        ratingEventFilter.reasonCodes = filter.reasonCodes;
      }

      repoOptions.filter = ratingEventFilter;
    }

    // Query repository
    const result = await this.ratingEventRepo.findEventsPaginated(userId, repoOptions);

    // Convert domain entities to DTOs
    const entries: LedgerEntryDto[] = result.items.map(event => {
      const dto: LedgerEntryDto = {
        id: event.id.value,
        userId: event.userId,
        dimension: event.dimension.value,
        delta: event.delta.value,
        occurredAt: event.occurredAt.toISOString(),
        createdAt: event.createdAt.toISOString(),
        source: event.source,
        reason: event.reason,
        visibility: event.visibility,
      };
      if (event.weight !== undefined) {
        dto.weight = event.weight;
      }
      return dto;
    });

    const nextOffset = result.nextOffset !== undefined ? result.nextOffset : null;

    return {
      entries,
      pagination: {
        total: result.total,
        limit: result.limit,
        offset: result.offset,
        hasMore: result.hasMore,
        nextOffset,
      },
    };
  }
}
