package space.luminic.budgerapp.services import org.bson.types.ObjectId import org.springframework.data.domain.Sort import org.springframework.data.domain.Sort.Direction import org.springframework.security.core.context.ReactiveSecurityContextHolder import org.springframework.stereotype.Service import reactor.core.publisher.Mono import space.luminic.budgerapp.models.Space import space.luminic.budgerapp.models.SpaceInvite import space.luminic.budgerapp.models.Transaction import space.luminic.budgerapp.repos.BudgetRepo import space.luminic.budgerapp.repos.SpaceRepo import space.luminic.budgerapp.repos.UserRepo import java.time.LocalDateTime import java.util.UUID @Service class SpaceService( private val spaceRepo: SpaceRepo, private val userService: UserService, private val budgetRepo: BudgetRepo, private val userRepo: UserRepo ) { fun isValidRequest(spaceId: String): Mono { return ReactiveSecurityContextHolder.getContext() .map { it.authentication } .flatMap { authentication -> val username = authentication.name // Получаем пользователя по имени userService.getByUsername(username) .switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username"))) .flatMap { user -> // Получаем пространство по ID spaceRepo.findById(spaceId) .switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for id: $spaceId"))) .flatMap { space -> // Проверяем доступ пользователя к пространству if (space.users.none { it.id.toString() == user.id }) { return@flatMap Mono.error(IllegalArgumentException("User does not have access to this Space")) } // Если проверка прошла успешно, возвращаем пространство Mono.just(space) } } } } fun getSpaces(): Mono> { return ReactiveSecurityContextHolder.getContext() .map { it.authentication } .flatMap { authentication -> val username = authentication.name userService.getByUsername(username) .switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username"))) .flatMapMany { user -> spaceRepo.findByArrayElement(ObjectId(user.id!!)) } .collectList() // Возвращаем Mono> } } fun getSpace(spaceId: String): Mono { return spaceRepo.findById(spaceId) .switchIfEmpty(Mono.error(IllegalArgumentException("SpaceId not found for spaceId: $spaceId"))) } fun createSpace(space: Space): Mono { return ReactiveSecurityContextHolder.getContext() .map { it.authentication } .flatMap { authentication -> val username = authentication.name userService.getByUsername(username) .switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username"))) .flatMap { user -> space.owner = user space.users.add(user) spaceRepo.save(space) } } } fun deleteSpace(spaceId: String): Mono { return budgetRepo.findBySpaceId(ObjectId(spaceId), Sort.by(Direction.DESC, "dateFrom")) .flatMap { budget -> budgetRepo.delete(budget) // Удаляем все бюджеты, связанные с этим Space } .then(spaceRepo.deleteById(spaceId)) // Затем удаляем сам Space } fun createInviteSpace(spaceId: String): Mono { return ReactiveSecurityContextHolder.getContext() .map { it.authentication } .flatMap { authentication -> val username = authentication.name userService.getByUsername(username) .switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username"))) .flatMap { user -> spaceRepo.findById(spaceId) .switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for id: $spaceId"))) .flatMap { space -> if (space.users.none { it.id.toString() == user.id }) { return@flatMap Mono.error(IllegalArgumentException("User does not have access to this Space")) } val invite = SpaceInvite( UUID.randomUUID().toString().split("-")[0], user, LocalDateTime.now().plusHours(1), ) space.invites.add(invite) // Сохраняем изменения и возвращаем созданное приглашение spaceRepo.save(space).thenReturn(invite) } } } } fun acceptInvite(code: String): Mono { return ReactiveSecurityContextHolder.getContext() .map { it.authentication } .flatMap { authentication -> val username = authentication.name userService.getByUsername(username) .switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username"))) .flatMap { user -> spaceRepo.findSpaceByInvites(code) .switchIfEmpty(Mono.error(IllegalArgumentException("Space with invite code: $code not found"))) .flatMap { space -> val invite = space.invites.find { it.code == code } // Проверяем, есть ли инвайт и не истек ли он if (invite == null || invite.activeTill.isBefore(LocalDateTime.now())) { return@flatMap Mono.error(IllegalArgumentException("Invite is invalid or expired")) } // Проверяем, не является ли пользователь уже участником if (space.users.any { it.id == user.id }) { return@flatMap Mono.error(IllegalArgumentException("User is already a member of this Space")) } // Добавляем пользователя и удаляем использованный инвайт space.users.add(user) space.invites.remove(invite) spaceRepo.save(space) } } } } fun leaveSpace(spaceId: String): Mono { return ReactiveSecurityContextHolder.getContext() .map { it.authentication } .flatMap { authentication -> val username = authentication.name userService.getByUsername(username) .switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username"))) .flatMap { user -> spaceRepo.findById(spaceId) .switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for id: $spaceId"))) .flatMap { space -> if (space.users.none { it.id.toString() == user.id }) { return@flatMap Mono.error(IllegalArgumentException("User does not have access to this Space")) } // Удаляем пользователя из массива space.users.removeIf { it.id == user.id } // Сохраняем изменения spaceRepo.save(space).then() // .then() для Mono } } } } fun kickMember(spaceId: String, kickedUsername: String): Mono { return ReactiveSecurityContextHolder.getContext() .map { it.authentication } .flatMap { authentication -> val username = authentication.name // Получаем текущего пользователя userService.getByUsername(username) .switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $username"))) .flatMap { user -> // Получаем пользователя, которого нужно исключить userService.getByUsername(kickedUsername) .switchIfEmpty(Mono.error(IllegalArgumentException("User not found for username: $kickedUsername"))) .flatMap { kickedUser -> // Получаем пространство spaceRepo.findById(spaceId) .switchIfEmpty(Mono.error(IllegalArgumentException("Space not found for id: $spaceId"))) .flatMap { space -> // Проверяем, является ли текущий пользователь владельцем if (space.owner?.id != user.id) { return@flatMap Mono.error(IllegalArgumentException("Only owners allowed for this action")) } // Проверяем, что пользователь, которого нужно исключить, присутствует в списке пользователей val userToKick = space.users.find { it.username == kickedUsername } if (userToKick != null) { // Удаляем пользователя из пространства space.users.removeIf { it.username == kickedUsername } // Сохраняем изменения return@flatMap spaceRepo.save(space).then() } else { return@flatMap Mono.error(IllegalArgumentException("User not found in this space")) } } } } } } // fun regenSpaces(): Mono> { // return spaceRepo.findAll() // .flatMap { space -> // userService.getUsers() // .flatMap { users -> // if (users.isEmpty()) { // return@flatMap Mono.error(IllegalStateException("No users found")) // } // val updatedSpace = space.copy(owner = users.first()) // Создаем копию (если `Space` data class) // spaceRepo.save(updatedSpace) // } // } // .collectList() // } }