import { Injectable, Inject } from '@nestjs/common';
import type { RecordEngagementInputDTO } from '../dtos/RecordEngagementInputDTO';
import type { RecordEngagementOutputDTO } from '../dtos/RecordEngagementOutputDTO';
import type { IEngagementRepository } from '@core/analytics/domain/repositories/IEngagementRepository';
import type { Logger } from '@core/shared/application';
import { EngagementEvent } from '@core/analytics/domain/entities/EngagementEvent';

type RecordEngagementInput = RecordEngagementInputDTO;
type RecordEngagementOutput = RecordEngagementOutputDTO;

const Logger_TOKEN = 'Logger_TOKEN';
const IENGAGEMENT_REPO_TOKEN = 'IEngagementRepository_TOKEN';

@Injectable()
export class RecordEngagementUseCase {
  constructor(
    @Inject(IENGAGEMENT_REPO_TOKEN) private readonly engagementRepository: IEngagementRepository,
    @Inject(Logger_TOKEN) private readonly logger: Logger,
  ) {}

  async execute(input: RecordEngagementInput): Promise<RecordEngagementOutput> {
    this.logger.debug('Executing RecordEngagementUseCase', { input });
    try {
      const eventId = `eng-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;

      const baseProps: Omit<Parameters<typeof EngagementEvent.create>[0], 'timestamp'> = {
        id: eventId,
        action: input.action as any, // Cast to any to bypass strict type checking, will resolve with proper domain layer alignment
        entityType: input.entityType as any, // Cast to any to bypass strict type checking, will resolve with proper domain layer alignment
        entityId: input.entityId,
        actorType: input.actorType,
        sessionId: input.sessionId,
      };

      const event = EngagementEvent.create({
        ...baseProps,
        ...(input.actorId !== undefined ? { actorId: input.actorId } : {}),
        ...(input.metadata !== undefined ? { metadata: input.metadata } : {}),
      });

      await this.engagementRepository.save(event);
      this.logger.info('Engagement recorded successfully', { eventId, input });

      return {
        eventId,
        engagementWeight: event.getEngagementWeight(),
      };
    } catch (error) {
      this.logger.error('Error recording engagement', error, { input });
      throw error;
    }
  }
}