import { ListUsersInput, ListUsersResult, ListUsersUseCase } from '@core/admin/application/use-cases/ListUsersUseCase';
import type { AdminUser } from '@core/admin/domain/entities/AdminUser';
import { Injectable } from '@nestjs/common';
import { DashboardStatsResponseDto } from './dto/DashboardStatsResponseDto';
import { UserListResponseDto, UserResponseDto } from './dtos/UserResponseDto';
import { GetDashboardStatsInput, GetDashboardStatsUseCase } from './use-cases/GetDashboardStatsUseCase';

@Injectable()
export class AdminService {
  constructor(
    private readonly listUsersUseCase: ListUsersUseCase,
    private readonly getDashboardStatsUseCase: GetDashboardStatsUseCase,
  ) {}

  async listUsers(input: ListUsersInput): Promise<UserListResponseDto> {
    const result = await this.listUsersUseCase.execute(input);

    if (result.isErr()) {
      const error = result.unwrapErr();
      throw new Error(`${error.code}: ${error.details.message}`);
    }

    const data = result.unwrap();
    return this.toListResponseDto(data);
  }

  async getDashboardStats(input: GetDashboardStatsInput): Promise<DashboardStatsResponseDto> {
    const result = await this.getDashboardStatsUseCase.execute(input);

    if (result.isErr()) {
      const error = result.unwrapErr();
      throw new Error(`${error.code}: ${error.details.message}`);
    }

    const data = result.unwrap();
    return data;
  }

  private toListResponseDto(result: ListUsersResult): UserListResponseDto {
    return {
      users: result.users.map(user => this.toUserResponse(user)),
      total: result.total,
      page: result.page,
      limit: result.limit,
      totalPages: result.totalPages,
    };
  }

  private toUserResponse(user: AdminUser | Record<string, unknown>): 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;
      const response: UserResponseDto = {
        id: domainUser.id.value,
        email: domainUser.email.value,
        displayName: domainUser.displayName,
        roles: domainUser.roles.map(r => r.value),
        status: domainUser.status.value,
        isSystemAdmin: domainUser.isSystemAdmin(),
        createdAt: domainUser.createdAt,
        updatedAt: domainUser.updatedAt,
      };
      if (domainUser.lastLoginAt) response.lastLoginAt = domainUser.lastLoginAt;
      if (domainUser.primaryDriverId) response.primaryDriverId = domainUser.primaryDriverId;
      return response;
    } else {
      // Plain object (for tests)
      const plainUser = user as Record<string, unknown>;
      const response: UserResponseDto = {
        id: plainUser.id as string,
        email: plainUser.email as string,
        displayName: plainUser.displayName as string,
        roles: plainUser.roles as string[],
        status: plainUser.status as string,
        isSystemAdmin: plainUser.isSystemAdmin as boolean,
        createdAt: plainUser.createdAt as Date,
        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;
    }
  }
}
