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

export type GetUserInput = {
  userId: string;
};

export type GetUserResult = {
  user: User;
};

export type GetUserErrorCode = 'USER_NOT_FOUND' | 'REPOSITORY_ERROR';

export type GetUserApplicationError = ApplicationErrorCode<
  GetUserErrorCode,
  { message: string }
>;

export class GetUserUseCase implements UseCase<GetUserInput, GetUserResult, GetUserErrorCode> {
  constructor(
    private readonly userRepo: IUserRepository,
    private readonly logger: Logger,
    private readonly output: UseCaseOutputPort<Result<GetUserResult, GetUserApplicationError>>,
  ) {}

  async execute(input: GetUserInput): Promise<Result<GetUserResult, GetUserApplicationError>> {
    try {
      const stored = await this.userRepo.findById(input.userId);
      if (!stored) {
        const result = Result.err<GetUserResult, GetUserApplicationError>({
          code: 'USER_NOT_FOUND',
          details: { message: 'User not found' },
        });
        this.output.present(result);
        return result;
      }

      const user = User.fromStored(stored);
      const result = Result.ok<GetUserResult, GetUserApplicationError>({ user });
      this.output.present(result);
      return result;
    } catch (error) {
      const message =
        error instanceof Error && error.message ? error.message : 'Failed to get user';

      this.logger.error('GetUserUseCase.execute failed', error instanceof Error ? error : undefined, {
        input,
      });

      const result = Result.err<GetUserResult, GetUserApplicationError>({
        code: 'REPOSITORY_ERROR',
        details: { message },
      });
      this.output.present(result);
      return result;
    }
  }
}