import type { UseCase } from '@core/shared/application/UseCase';
import type { Logger } from '@core/shared/domain/Logger';
import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import { PageView } from '../../domain/entities/PageView';
import type { EntityType, VisitorType } from '../../domain/types/PageView';
import type { PageViewRepository } from '../repositories/PageViewRepository';

export interface RecordPageViewInput {
  entityType: EntityType;
  entityId: string;
  visitorId?: string;
  visitorType: VisitorType;
  sessionId: string;
  referrer?: string;
  userAgent?: string;
  country?: string;
}

export interface RecordPageViewOutput {
  pageViewId: string;
}

export type RecordPageViewErrorCode = 'REPOSITORY_ERROR';

export class RecordPageViewUseCase implements UseCase<RecordPageViewInput, RecordPageViewOutput, RecordPageViewErrorCode> {
  constructor(
    private readonly pageViewRepository: PageViewRepository,
    private readonly logger: Logger,
  ) {}

  async execute(input: RecordPageViewInput): Promise<Result<RecordPageViewOutput, ApplicationErrorCode<RecordPageViewErrorCode, { message: string }>>> {
    try {
      type PageViewCreateProps = Parameters<(typeof PageView)['create']>[0];

      const props: PageViewCreateProps = {
        id: crypto.randomUUID(),
        entityType: input.entityType,
        entityId: input.entityId,
        visitorType: input.visitorType,
        sessionId: input.sessionId,
        ...(input.visitorId !== undefined ? { visitorId: input.visitorId } : {}),
        ...(input.referrer !== undefined ? { referrer: input.referrer } : {}),
        ...(input.userAgent !== undefined ? { userAgent: input.userAgent } : {}),
        ...(input.country !== undefined ? { country: input.country } : {}),
      };

      const pageView = PageView.create(props);

      await this.pageViewRepository.save(pageView);

      const resultModel: RecordPageViewOutput = {
        pageViewId: pageView.id,
      };

      this.logger.info('Page view recorded', {
        pageViewId: pageView.id,
        entityId: input.entityId,
        entityType: input.entityType,
      });

      return Result.ok(resultModel);
    } catch (error) {
      const err = error as Error;
      this.logger.error('Failed to record page view', err, { input });
      return Result.err({
        code: 'REPOSITORY_ERROR',
        details: { message: err.message ?? 'Failed to record page view' },
      });
    }
  }
}