import { GetAnalyticsMetricsUseCase } from '@core/analytics/application/use-cases/GetAnalyticsMetricsUseCase';
import { GetDashboardDataUseCase } from '@core/analytics/application/use-cases/GetDashboardDataUseCase';
import { RecordEngagementUseCase } from '@core/analytics/application/use-cases/RecordEngagementUseCase';
import { RecordPageViewUseCase } from '@core/analytics/application/use-cases/RecordPageViewUseCase';
import { Inject, Injectable } from '@nestjs/common';
import type { GetAnalyticsMetricsOutputDTO } from './dtos/GetAnalyticsMetricsOutputDTO';
import type { GetDashboardDataOutputDTO } from './dtos/GetDashboardDataOutputDTO';
import type { RecordEngagementInputDTO } from './dtos/RecordEngagementInputDTO';
import type { RecordEngagementOutputDTO } from './dtos/RecordEngagementOutputDTO';
import type { RecordPageViewInputDTO } from './dtos/RecordPageViewInputDTO';
import type { RecordPageViewOutputDTO } from './dtos/RecordPageViewOutputDTO';
import { GetAnalyticsMetricsPresenter } from './presenters/GetAnalyticsMetricsPresenter';
import { GetDashboardDataPresenter } from './presenters/GetDashboardDataPresenter';
import { RecordEngagementPresenter } from './presenters/RecordEngagementPresenter';
import { RecordPageViewPresenter } from './presenters/RecordPageViewPresenter';

type RecordPageViewInput = RecordPageViewInputDTO;
type RecordEngagementInput = RecordEngagementInputDTO;

@Injectable()
export class AnalyticsService {
  constructor(
    @Inject(RecordPageViewUseCase) private readonly recordPageViewUseCase: RecordPageViewUseCase,
    @Inject(RecordEngagementUseCase) private readonly recordEngagementUseCase: RecordEngagementUseCase,
    @Inject(GetDashboardDataUseCase) private readonly getDashboardDataUseCase: GetDashboardDataUseCase,
    @Inject(GetAnalyticsMetricsUseCase) private readonly getAnalyticsMetricsUseCase: GetAnalyticsMetricsUseCase,
    @Inject(RecordPageViewPresenter) private readonly recordPageViewPresenter: RecordPageViewPresenter,
    @Inject(RecordEngagementPresenter) private readonly recordEngagementPresenter: RecordEngagementPresenter,
    @Inject(GetDashboardDataPresenter) private readonly getDashboardDataPresenter: GetDashboardDataPresenter,
    @Inject(GetAnalyticsMetricsPresenter) private readonly getAnalyticsMetricsPresenter: GetAnalyticsMetricsPresenter,
  ) {}

  async recordPageView(input: RecordPageViewInput): Promise<RecordPageViewOutputDTO> {
    const result = await this.recordPageViewUseCase.execute(input);
    if (result.isErr()) {
      const error = result.unwrapErr();
      throw new Error(error.details?.message ?? 'Failed to record page view');
    }

    return this.recordPageViewPresenter.transform(result.unwrap());
  }

  async recordEngagement(input: RecordEngagementInput): Promise<RecordEngagementOutputDTO> {
    const result = await this.recordEngagementUseCase.execute(input);
    if (result.isErr()) {
      const error = result.unwrapErr();
      throw new Error(error.details?.message ?? 'Failed to record engagement');
    }

    return this.recordEngagementPresenter.transform(result.unwrap());
  }

  async getDashboardData(): Promise<GetDashboardDataOutputDTO> {
    const result = await this.getDashboardDataUseCase.execute();
    if (result.isErr()) {
      const error = result.unwrapErr();
      throw new Error(error.details?.message ?? 'Failed to get dashboard data');
    }

    return this.getDashboardDataPresenter.transform(result.unwrap());
  }

  async getAnalyticsMetrics(): Promise<GetAnalyticsMetricsOutputDTO> {
    const result = await this.getAnalyticsMetricsUseCase.execute({});
    if (result.isErr()) {
      const error = result.unwrapErr();
      throw new Error(error.details?.message ?? 'Failed to get analytics metrics');
    }

    return this.getAnalyticsMetricsPresenter.transform(result.unwrap());
  }
}