/**
 * Use Case: RejectSponsorshipRequestUseCase
 *
 * Allows an entity owner to reject a sponsorship request.
 */

import type { Logger, UseCaseOutputPort } from '@core/shared/application';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { ISponsorshipRequestRepository } from '../../domain/repositories/ISponsorshipRequestRepository';

export type RejectSponsorshipRequestInput = {
  requestId: string;
  respondedBy: string;
  reason?: string;
};

export type RejectSponsorshipRequestResult = {
  requestId: string;
  status: 'rejected';
  respondedAt: Date;
  rejectionReason: string | undefined;
};

export type RejectSponsorshipRequestErrorCode =
  | 'SPONSORSHIP_REQUEST_NOT_FOUND'
  | 'SPONSORSHIP_REQUEST_NOT_PENDING'
  | 'REPOSITORY_ERROR';

export class RejectSponsorshipRequestUseCase {
  constructor(
    private readonly sponsorshipRequestRepo: ISponsorshipRequestRepository,
    private readonly logger: Logger,
    private readonly output: UseCaseOutputPort<RejectSponsorshipRequestResult>,
  ) {}

  async execute(
    input: RejectSponsorshipRequestInput,
  ): Promise<
    Result<void, ApplicationErrorCode<RejectSponsorshipRequestErrorCode, { message: string }>>
  > {
    const { requestId, respondedBy, reason } = input;

    this.logger.debug('Executing RejectSponsorshipRequestUseCase', {
      requestId,
      respondedBy,
    });

    try {
      const request = await this.sponsorshipRequestRepo.findById(requestId);
      if (!request) {
        this.logger.warn('Sponsorship request not found', { requestId, respondedBy });
        return Result.err({
          code: 'SPONSORSHIP_REQUEST_NOT_FOUND',
          details: { message: 'Sponsorship request not found' },
        });
      }

      if (!request.isPending()) {
        this.logger.warn('Sponsorship request is not pending', {
          requestId,
          respondedBy,
          status: request.status,
        });
        return Result.err({
          code: 'SPONSORSHIP_REQUEST_NOT_PENDING',
          details: { message: 'Sponsorship request is not pending' },
        });
      }

      const rejectedRequest = request.reject(respondedBy, reason);
      await this.sponsorshipRequestRepo.update(rejectedRequest);

      const result: RejectSponsorshipRequestResult = {
        requestId: rejectedRequest.id,
        status: 'rejected',
        respondedAt: rejectedRequest.respondedAt ?? new Date(),
        rejectionReason: rejectedRequest.rejectionReason,
      };

      this.output.present(result);

      this.logger.info('Sponsorship request rejected successfully', {
        requestId,
        respondedBy,
      });

      return Result.ok(undefined);
    } catch (error) {
      const err = error instanceof Error ? error : new Error('Unknown error');
      this.logger.error('Failed to reject sponsorship request', err, {
        requestId,
        respondedBy,
      });

      return Result.err({
        code: 'REPOSITORY_ERROR',
        details: { message: err.message ?? 'Failed to reject sponsorship request' },
      });
    }
  }
}
