import { Injectable, BadRequestException, UnauthorizedException, NotFoundException } from '@nestjs/common'; import { RequestOtpDto } from '../dto/request-otp.dto'; import { CacheService } from '../../utils/cache.service'; import { SmsService } from '../../utils/sms.service'; import { UserService } from '../../users/user.service'; import { randomInt } from 'crypto'; import { JwtService } from '@nestjs/jwt'; import { AdminService } from '../../admin/admin.service'; import { AuthEntityType } from 'src/modules/auth/guards/auth.guard'; @Injectable() export class AuthService { constructor( private readonly cacheService: CacheService, private readonly smsService: SmsService, private readonly userService: UserService, private readonly jwtService: JwtService, private readonly adminService: AdminService, ) {} async requestOtp(dto: RequestOtpDto) { const { phone } = dto; const code = this.generateOtpCode(); await this.cacheService.set(`otp:${phone}`, code, 160); await this.smsService.sendOtp(phone, code); return { success: true, message: ' OTP sent successfully' }; } async requestOtpAdmin(dto: RequestOtpDto) { const { phone } = dto; const admin = await this.adminService.findByPhone(phone); if (!admin) { throw new NotFoundException(); } const code = this.generateOtpCode(); await this.cacheService.set(`otp-admin:${phone}`, code, 160); await this.smsService.sendOtp(phone, code); return { success: true, message: ' OTP sent successfully' }; } async verifyOtp(phone: string, code: string) { const cachedCode = await this.cacheService.get(`otp:${phone}`); if (!cachedCode) throw new BadRequestException('OTP expired or not found'); if (cachedCode !== code) throw new BadRequestException('Invalid OTP'); await this.cacheService.del(`otp:${phone}`); const user = await this.userService.findOrCreateByPhone(phone); const accessToken = await this.issueToken(user.id, AuthEntityType.USER); return { success: true, message: 'User registered successfully!', accessToken }; } async verifyOtpAdmin(phone: string, code: string) { const cachedCode = await this.cacheService.get(`otp-admin:${phone}`); if (!cachedCode) throw new BadRequestException('OTP expired or not found'); if (cachedCode !== code) throw new BadRequestException('Invalid OTP'); await this.cacheService.del(`otp:${phone}`); const admin = await this.adminService.findByPhone(phone); if (!admin) { throw new UnauthorizedException(); } const accessToken = await this.issueToken(admin.id.toString(), AuthEntityType.ADMIN); return { success: true, message: 'successfully!', accessToken }; } private generateOtpCode(): string { const code = randomInt(10000, 100000); return code.toString(); } private issueToken(id: string, entityType: AuthEntityType) { const payload = { sub: id, type: entityType, }; return this.jwtService.signAsync(payload); } }