import { GetBuildingChildDto } from '../dtos/get.building.dto'; import { SpaceTypeRepository } from '../../../libs/common/src/modules/space/repositories/space.repository'; import { Injectable, HttpException, HttpStatus, BadRequestException, } from '@nestjs/common'; import { SpaceRepository } from '@app/common/modules/space/repositories'; import { AddBuildingDto, AddUserBuildingDto } from '../dtos'; import { BuildingChildInterface, BuildingParentInterface, GetBuildingByUserUuidInterface, GetBuildingByUuidInterface, RenameBuildingByUuidInterface, } from '../interface/building.interface'; import { SpaceEntity } from '@app/common/modules/space/entities'; import { UpdateBuildingNameDto } from '../dtos/update.building.dto'; import { UserSpaceRepository } from '@app/common/modules/user/repositories'; @Injectable() export class BuildingService { constructor( private readonly spaceRepository: SpaceRepository, private readonly spaceTypeRepository: SpaceTypeRepository, private readonly userSpaceRepository: UserSpaceRepository, ) {} async addBuilding(addBuildingDto: AddBuildingDto) { try { const spaceType = await this.spaceTypeRepository.findOne({ where: { type: 'building', }, }); if (!spaceType) { throw new BadRequestException('Invalid building UUID'); } const building = await this.spaceRepository.save({ spaceName: addBuildingDto.buildingName, parent: { uuid: addBuildingDto.communityUuid }, spaceType: { uuid: spaceType.uuid }, }); return building; } catch (err) { if (err instanceof BadRequestException) { throw err; // Re-throw BadRequestException } else { throw new HttpException('Building not found', HttpStatus.NOT_FOUND); } } } async getBuildingByUuid( buildingUuid: string, ): Promise { try { const building = await this.spaceRepository.findOne({ where: { uuid: buildingUuid, spaceType: { type: 'building', }, }, relations: ['spaceType'], }); if ( !building || !building.spaceType || building.spaceType.type !== 'building' ) { throw new BadRequestException('Invalid building UUID'); } return { uuid: building.uuid, createdAt: building.createdAt, updatedAt: building.updatedAt, name: building.spaceName, type: building.spaceType.type, }; } catch (err) { if (err instanceof BadRequestException) { throw err; // Re-throw BadRequestException } else { throw new HttpException('Building not found', HttpStatus.NOT_FOUND); } } } async getBuildingChildByUuid( buildingUuid: string, getBuildingChildDto: GetBuildingChildDto, ): Promise { try { const { includeSubSpaces, page, pageSize } = getBuildingChildDto; const space = await this.spaceRepository.findOneOrFail({ where: { uuid: buildingUuid }, relations: ['children', 'spaceType'], }); if (!space || !space.spaceType || space.spaceType.type !== 'building') { throw new BadRequestException('Invalid building UUID'); } const totalCount = await this.spaceRepository.count({ where: { parent: { uuid: space.uuid } }, }); const children = await this.buildHierarchy( space, includeSubSpaces, 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('Building 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 !== 'building' && child.spaceType.type !== 'community', ) // Filter remaining building and community types .map((child) => ({ uuid: child.uuid, name: child.spaceName, type: child.spaceType.type, })); } const childHierarchies = await Promise.all( children .filter( (child) => child.spaceType.type !== 'building' && child.spaceType.type !== 'community', ) // Filter remaining building and community 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 getBuildingParentByUuid( buildingUuid: string, ): Promise { try { const building = await this.spaceRepository.findOne({ where: { uuid: buildingUuid, spaceType: { type: 'building', }, }, relations: ['spaceType', 'parent', 'parent.spaceType'], }); if ( !building || !building.spaceType || building.spaceType.type !== 'building' ) { throw new BadRequestException('Invalid building UUID'); } return { uuid: building.uuid, name: building.spaceName, type: building.spaceType.type, parent: { uuid: building.parent.uuid, name: building.parent.spaceName, type: building.parent.spaceType.type, }, }; } catch (err) { if (err instanceof BadRequestException) { throw err; // Re-throw BadRequestException } else { throw new HttpException('Building not found', HttpStatus.NOT_FOUND); } } } async getBuildingsByUserId( userUuid: string, ): Promise { try { const buildings = await this.userSpaceRepository.find({ relations: ['space', 'space.spaceType'], where: { user: { uuid: userUuid }, space: { spaceType: { type: 'building' } }, }, }); if (buildings.length === 0) { throw new HttpException( 'this user has no buildings', HttpStatus.NOT_FOUND, ); } const spaces = buildings.map((building) => ({ uuid: building.space.uuid, name: building.space.spaceName, type: building.space.spaceType.type, })); return spaces; } catch (err) { if (err instanceof HttpException) { throw err; } else { throw new HttpException('user not found', HttpStatus.NOT_FOUND); } } } async addUserBuilding(addUserBuildingDto: AddUserBuildingDto) { try { await this.userSpaceRepository.save({ user: { uuid: addUserBuildingDto.userUuid }, space: { uuid: addUserBuildingDto.buildingUuid }, }); } catch (err) { if (err.code === '23505') { throw new HttpException( 'User already belongs to this building', HttpStatus.BAD_REQUEST, ); } throw new HttpException( err.message || 'Internal Server Error', HttpStatus.INTERNAL_SERVER_ERROR, ); } } async renameBuildingByUuid( buildingUuid: string, updateBuildingNameDto: UpdateBuildingNameDto, ): Promise { try { const building = await this.spaceRepository.findOneOrFail({ where: { uuid: buildingUuid }, relations: ['spaceType'], }); if ( !building || !building.spaceType || building.spaceType.type !== 'building' ) { throw new BadRequestException('Invalid building UUID'); } await this.spaceRepository.update( { uuid: buildingUuid }, { spaceName: updateBuildingNameDto.buildingName }, ); // Fetch the updated building const updatedBuilding = await this.spaceRepository.findOneOrFail({ where: { uuid: buildingUuid }, relations: ['spaceType'], }); return { uuid: updatedBuilding.uuid, name: updatedBuilding.spaceName, type: updatedBuilding.spaceType.type, }; } catch (err) { if (err instanceof BadRequestException) { throw err; // Re-throw BadRequestException } else { throw new HttpException('Building not found', HttpStatus.NOT_FOUND); } } } }