import { GetUnitChildDto } from '../dtos/get.unit.dto'; import { SpaceTypeRepository } from '../../../libs/common/src/modules/space-type/repositories/space.type.repository'; import { Injectable, HttpException, HttpStatus, BadRequestException, } from '@nestjs/common'; import { SpaceRepository } from '@app/common/modules/space/repositories'; import { AddUnitDto, AddUserUnitDto } from '../dtos'; import { UnitChildInterface, UnitParentInterface, GetUnitByUuidInterface, RenameUnitByUuidInterface, GetUnitByUserUuidInterface, } from '../interface/unit.interface'; import { SpaceEntity } from '@app/common/modules/space/entities'; import { UpdateUnitNameDto } from '../dtos/update.unit.dto'; import { UserSpaceRepository } from '@app/common/modules/user-space/repositories'; @Injectable() export class UnitService { constructor( private readonly spaceRepository: SpaceRepository, private readonly spaceTypeRepository: SpaceTypeRepository, private readonly userSpaceRepository: UserSpaceRepository, ) {} async addUnit(addUnitDto: AddUnitDto) { try { const spaceType = await this.spaceTypeRepository.findOne({ where: { type: 'unit', }, }); const unit = await this.spaceRepository.save({ spaceName: addUnitDto.unitName, parent: { uuid: addUnitDto.floorUuid }, spaceType: { uuid: spaceType.uuid }, }); return unit; } catch (err) { throw new HttpException(err.message, HttpStatus.INTERNAL_SERVER_ERROR); } } async getUnitByUuid(unitUuid: string): Promise { try { const unit = await this.spaceRepository.findOne({ where: { uuid: unitUuid, spaceType: { type: 'unit', }, }, relations: ['spaceType'], }); if (!unit || !unit.spaceType || unit.spaceType.type !== 'unit') { throw new BadRequestException('Invalid unit UUID'); } return { uuid: unit.uuid, createdAt: unit.createdAt, updatedAt: unit.updatedAt, name: unit.spaceName, type: unit.spaceType.type, }; } catch (err) { if (err instanceof BadRequestException) { throw err; // Re-throw BadRequestException } else { throw new HttpException('Unit not found', HttpStatus.NOT_FOUND); } } } async getUnitChildByUuid( unitUuid: string, getUnitChildDto: GetUnitChildDto, ): Promise { try { const { page, pageSize } = getUnitChildDto; const space = await this.spaceRepository.findOneOrFail({ where: { uuid: unitUuid }, relations: ['children', 'spaceType'], }); if (!space || !space.spaceType || space.spaceType.type !== 'unit') { throw new BadRequestException('Invalid unit UUID'); } const totalCount = await this.spaceRepository.count({ where: { parent: { uuid: space.uuid } }, }); const children = await this.buildHierarchy(space, false, page, pageSize); return { uuid: space.uuid, name: space.spaceName, type: space.spaceType.type, totalCount, children, }; } catch (err) { if (err instanceof BadRequestException) { throw err; // Re-throw BadRequestException } else { throw new HttpException('Unit not found', HttpStatus.NOT_FOUND); } } } private async buildHierarchy( space: SpaceEntity, includeSubSpaces: boolean, page: number, pageSize: number, ): Promise { const children = await this.spaceRepository.find({ where: { parent: { uuid: space.uuid } }, relations: ['spaceType'], skip: (page - 1) * pageSize, take: pageSize, }); if (!children || children.length === 0 || !includeSubSpaces) { return children .filter( (child) => child.spaceType.type !== 'unit' && child.spaceType.type !== 'floor' && child.spaceType.type !== 'community' && child.spaceType.type !== 'unit', ) // Filter remaining unit and floor and community and unit types .map((child) => ({ uuid: child.uuid, name: child.spaceName, type: child.spaceType.type, })); } const childHierarchies = await Promise.all( children .filter( (child) => child.spaceType.type !== 'unit' && child.spaceType.type !== 'floor' && child.spaceType.type !== 'community' && child.spaceType.type !== 'unit', ) // Filter remaining unit and floor and community and unit types .map(async (child) => ({ uuid: child.uuid, name: child.spaceName, type: child.spaceType.type, children: await this.buildHierarchy(child, true, 1, pageSize), })), ); return childHierarchies; } async getUnitParentByUuid(unitUuid: string): Promise { try { const unit = await this.spaceRepository.findOne({ where: { uuid: unitUuid, spaceType: { type: 'unit', }, }, relations: ['spaceType', 'parent', 'parent.spaceType'], }); if (!unit || !unit.spaceType || unit.spaceType.type !== 'unit') { throw new BadRequestException('Invalid unit UUID'); } return { uuid: unit.uuid, name: unit.spaceName, type: unit.spaceType.type, parent: { uuid: unit.parent.uuid, name: unit.parent.spaceName, type: unit.parent.spaceType.type, }, }; } catch (err) { if (err instanceof BadRequestException) { throw err; // Re-throw BadRequestException } else { throw new HttpException('Unit not found', HttpStatus.NOT_FOUND); } } } async getUnitsByUserId( userUuid: string, ): Promise { try { const units = await this.userSpaceRepository.find({ relations: ['space', 'space.spaceType'], where: { user: { uuid: userUuid }, space: { spaceType: { type: 'unit' } }, }, }); if (units.length === 0) { throw new HttpException('this user has no units', HttpStatus.NOT_FOUND); } const spaces = units.map((unit) => ({ uuid: unit.space.uuid, name: unit.space.spaceName, type: unit.space.spaceType.type, })); return spaces; } catch (err) { if (err instanceof HttpException) { throw err; } else { throw new HttpException('user not found', HttpStatus.NOT_FOUND); } } } async addUserUnit(addUserUnitDto: AddUserUnitDto) { try { await this.userSpaceRepository.save({ user: { uuid: addUserUnitDto.userUuid }, space: { uuid: addUserUnitDto.unitUuid }, }); } catch (err) { if (err.code === '23505') { throw new HttpException( 'User already belongs to this unit', HttpStatus.BAD_REQUEST, ); } throw new HttpException( err.message || 'Internal Server Error', HttpStatus.INTERNAL_SERVER_ERROR, ); } } async renameUnitByUuid( unitUuid: string, updateUnitNameDto: UpdateUnitNameDto, ): Promise { try { const unit = await this.spaceRepository.findOneOrFail({ where: { uuid: unitUuid }, relations: ['spaceType'], }); if (!unit || !unit.spaceType || unit.spaceType.type !== 'unit') { throw new BadRequestException('Invalid unit UUID'); } await this.spaceRepository.update( { uuid: unitUuid }, { spaceName: updateUnitNameDto.unitName }, ); // Fetch the updated unit const updatedUnit = await this.spaceRepository.findOneOrFail({ where: { uuid: unitUuid }, relations: ['spaceType'], }); return { uuid: updatedUnit.uuid, name: updatedUnit.spaceName, type: updatedUnit.spaceType.type, }; } catch (err) { if (err instanceof BadRequestException) { throw err; // Re-throw BadRequestException } else { throw new HttpException('Unit not found', HttpStatus.NOT_FOUND); } } } }