import { ListUsersResult } from '@core/admin/application/use-cases/ListUsersUseCase';
import type { AdminUser } from '@core/admin/domain/entities/AdminUser';
import { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
import { UserListResponseDto, UserResponseDto } from '../dtos/UserResponseDto';

export type ListUsersViewModel = UserListResponseDto;

/**
 * Presenter to convert application layer result to API response DTO
 * Implements UseCaseOutputPort to receive results from the use case
 */
export class ListUsersPresenter implements UseCaseOutputPort<ListUsersResult> {
  private viewModel!: ListUsersViewModel;

  present(result: ListUsersResult): void {
    this.viewModel = {
      users: result.users.map(user => this.toUserResponse(user)),
      total: result.total,
      page: result.page,
      limit: result.limit,
      totalPages: result.totalPages,
    };
  }

  getViewModel(): ListUsersViewModel {
    if (!this.viewModel) {
      throw new Error('Presenter not presented');
    }
    return this.viewModel;
  }

  // Static method for backward compatibility with tests
  static toResponse(result: ListUsersResult): UserListResponseDto {
    const presenter = new ListUsersPresenter();
    presenter.present(result);
    return presenter.getViewModel();
  }

  private toUserResponse(user: AdminUser | Record<string, unknown>): UserResponseDto {
    const response = new UserResponseDto();
    
    // Handle both domain objects and plain objects
    if (user.id && typeof user.id === 'object' && 'value' in (user.id as Record<string, unknown>)) {
      // Domain object
      const domainUser = user as AdminUser;
      response.id = domainUser.id.value;
      response.email = domainUser.email.value;
      response.displayName = domainUser.displayName;
      response.roles = domainUser.roles.map(r => r.value);
      response.status = domainUser.status.value;
      response.isSystemAdmin = domainUser.isSystemAdmin();
      response.createdAt = domainUser.createdAt;
      response.updatedAt = domainUser.updatedAt;
      
      if (domainUser.lastLoginAt) {
        response.lastLoginAt = domainUser.lastLoginAt;
      }
      
      if (domainUser.primaryDriverId) {
        response.primaryDriverId = domainUser.primaryDriverId;
      }
    } else {
      // Plain object (for tests)
      const plainUser = user as Record<string, unknown>;
      response.id = plainUser.id as string;
      response.email = plainUser.email as string;
      response.displayName = plainUser.displayName as string;
      response.roles = plainUser.roles as string[];
      response.status = plainUser.status as string;
      response.isSystemAdmin = plainUser.isSystemAdmin as boolean;
      response.createdAt = plainUser.createdAt as Date;
      response.updatedAt = plainUser.updatedAt as Date;
      
      if (plainUser.lastLoginAt) {
        response.lastLoginAt = plainUser.lastLoginAt as Date;
      }
      
      if (plainUser.primaryDriverId) {
        response.primaryDriverId = plainUser.primaryDriverId as string;
      }
    }

    return response;
  }
}