import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
import { Result } from '@core/shared/application/Result';
import type { UseCase } from '@core/shared/application';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Logger } from '@core/shared/application/Logger';
import type { IDriverRepository } from '../../domain/repositories/IDriverRepository';
import type { Driver } from '../../domain/entities/Driver';

export type UpdateDriverProfileInput = {
  driverId: string;
  bio?: string;
  country?: string;
};

export type UpdateDriverProfileResult = Driver;

export type UpdateDriverProfileErrorCode =
  | 'DRIVER_NOT_FOUND'
  | 'INVALID_PROFILE_DATA'
  | 'REPOSITORY_ERROR';

/**
 * Application use case responsible for updating basic driver profile details.
 * Encapsulates domain entity mutation. Mapping to DTOs is handled by presenters
 * in the presentation layer through the output port.
 */
export class UpdateDriverProfileUseCase
  implements UseCase<UpdateDriverProfileInput, void, UpdateDriverProfileErrorCode>
{
  constructor(
    private readonly driverRepository: IDriverRepository,
    private readonly logger: Logger,
    private readonly output: UseCaseOutputPort<UpdateDriverProfileResult>,
  ) {}

  async execute(
    input: UpdateDriverProfileInput,
  ): Promise<
    Result<void, ApplicationErrorCode<UpdateDriverProfileErrorCode, { message: string }>>
  > {
    const { driverId, bio, country } = input;

    if ((bio !== undefined && bio.trim().length === 0) || (country !== undefined && country.trim().length === 0)) {
      return Result.err({
        code: 'INVALID_PROFILE_DATA',
        details: {
          message: 'Profile data is invalid',
        },
      });
    }

    try {
      const existing = await this.driverRepository.findById(driverId);
      if (!existing) {
        return Result.err({
          code: 'DRIVER_NOT_FOUND',
          details: {
            message: `Driver with id ${driverId} not found`,
          },
        });
      }

      const updated: Driver = existing.update({
        ...(bio !== undefined ? { bio } : {}),
        ...(country !== undefined ? { country } : {}),
      });

      await this.driverRepository.update(updated);

      this.output.present(updated);

      return Result.ok(undefined);
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Failed to update driver profile';

      this.logger.error('Failed to update driver profile', error instanceof Error ? error : undefined, {
        driverId,
      });

      return Result.err({
        code: 'REPOSITORY_ERROR',
        details: {
          message,
        },
      });
    }
  }
}