import type { GetAnalyticsMetricsOutput } from '@core/analytics/application/use-cases/GetAnalyticsMetricsUseCase';
import type { RecordEngagementOutput } from '@core/analytics/application/use-cases/RecordEngagementUseCase';
import type { RecordPageViewOutput } from '@core/analytics/application/use-cases/RecordPageViewUseCase';
import type { IEngagementRepository } from '@core/analytics/domain/repositories/IEngagementRepository';
import type { IPageViewRepository } from '@core/analytics/application/repositories/IPageViewRepository';
import type { Logger, UseCaseOutputPort } from '@core/shared/application';
import { Provider } from '@nestjs/common';

import {
  ANALYTICS_ENGAGEMENT_REPOSITORY_TOKEN,
  ANALYTICS_PAGE_VIEW_REPOSITORY_TOKEN,
} from '../../persistence/analytics/AnalyticsPersistenceTokens';

const LOGGER_TOKEN = 'Logger';

const RECORD_PAGE_VIEW_OUTPUT_PORT_TOKEN = 'RecordPageViewOutputPort_TOKEN';
const RECORD_ENGAGEMENT_OUTPUT_PORT_TOKEN = 'RecordEngagementOutputPort_TOKEN';
const GET_DASHBOARD_DATA_OUTPUT_PORT_TOKEN = 'GetDashboardDataOutputPort_TOKEN';
const GET_ANALYTICS_METRICS_OUTPUT_PORT_TOKEN = 'GetAnalyticsMetricsOutputPort_TOKEN';

import { GetAnalyticsMetricsUseCase } from '@core/analytics/application/use-cases/GetAnalyticsMetricsUseCase';
import { GetDashboardDataOutput, 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 { AnalyticsService } from './AnalyticsService';
import { GetAnalyticsMetricsPresenter } from './presenters/GetAnalyticsMetricsPresenter';
import { GetDashboardDataPresenter } from './presenters/GetDashboardDataPresenter';
import { RecordEngagementPresenter } from './presenters/RecordEngagementPresenter';
import { RecordPageViewPresenter } from './presenters/RecordPageViewPresenter';

export const AnalyticsProviders: Provider[] = [
  AnalyticsService,
  RecordPageViewPresenter,
  RecordEngagementPresenter,
  GetDashboardDataPresenter,
  GetAnalyticsMetricsPresenter,
  {
    provide: RECORD_PAGE_VIEW_OUTPUT_PORT_TOKEN,
    useExisting: RecordPageViewPresenter,
  },
  {
    provide: RECORD_ENGAGEMENT_OUTPUT_PORT_TOKEN,
    useExisting: RecordEngagementPresenter,
  },
  {
    provide: GET_DASHBOARD_DATA_OUTPUT_PORT_TOKEN,
    useExisting: GetDashboardDataPresenter,
  },
  {
    provide: GET_ANALYTICS_METRICS_OUTPUT_PORT_TOKEN,
    useExisting: GetAnalyticsMetricsPresenter,
  },
  {
    provide: RecordPageViewUseCase,
    useFactory: (repo: IPageViewRepository, logger: Logger, output: UseCaseOutputPort<RecordPageViewOutput>) =>
      new RecordPageViewUseCase(repo, logger, output),
    inject: [ANALYTICS_PAGE_VIEW_REPOSITORY_TOKEN, LOGGER_TOKEN, RECORD_PAGE_VIEW_OUTPUT_PORT_TOKEN],
  },
  {
    provide: RecordEngagementUseCase,
    useFactory: (repo: IEngagementRepository, logger: Logger, output: UseCaseOutputPort<RecordEngagementOutput>) =>
      new RecordEngagementUseCase(repo, logger, output),
    inject: [ANALYTICS_ENGAGEMENT_REPOSITORY_TOKEN, LOGGER_TOKEN, RECORD_ENGAGEMENT_OUTPUT_PORT_TOKEN],
  },
  {
    provide: GetDashboardDataUseCase,
    useFactory: (logger: Logger, output: UseCaseOutputPort<GetDashboardDataOutput>) =>
      new GetDashboardDataUseCase(logger, output),
    inject: [LOGGER_TOKEN, GET_DASHBOARD_DATA_OUTPUT_PORT_TOKEN],
  },
  {
    provide: GetAnalyticsMetricsUseCase,
    useFactory: (logger: Logger, output: UseCaseOutputPort<GetAnalyticsMetricsOutput>, repo: IPageViewRepository) =>
      new GetAnalyticsMetricsUseCase(logger, output, repo),
    inject: [LOGGER_TOKEN, GET_ANALYTICS_METRICS_OUTPUT_PORT_TOKEN, ANALYTICS_PAGE_VIEW_REPOSITORY_TOKEN],
  },
];