package com.android.trisolarisserver.controller import com.android.trisolarisserver.controller.dto.AmenityResponse import com.android.trisolarisserver.controller.dto.AmenityUpsertRequest import com.android.trisolarisserver.models.room.RoomAmenity import com.android.trisolarisserver.repo.AppUserRepo import com.android.trisolarisserver.repo.RoomAmenityRepo import com.android.trisolarisserver.repo.RoomTypeRepo import com.android.trisolarisserver.security.MyPrincipal import org.springframework.http.HttpStatus import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.PutMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.ResponseStatus import org.springframework.web.bind.annotation.RestController import org.springframework.web.server.ResponseStatusException import java.util.UUID @RestController @RequestMapping("/amenities") class RoomAmenities( private val roomAmenityRepo: RoomAmenityRepo, private val roomTypeRepo: RoomTypeRepo, private val appUserRepo: AppUserRepo ) { @GetMapping fun listAmenities( @AuthenticationPrincipal principal: MyPrincipal? ): List { requirePrincipal(principal) return roomAmenityRepo.findAllByOrderByName().map { it.toResponse() } } @PostMapping @ResponseStatus(HttpStatus.CREATED) fun createAmenity( @AuthenticationPrincipal principal: MyPrincipal?, @RequestBody request: AmenityUpsertRequest ): AmenityResponse { requireSuperAdmin(principal) if (roomAmenityRepo.existsByName(request.name)) { throw ResponseStatusException(HttpStatus.CONFLICT, "Amenity already exists") } val amenity = RoomAmenity( name = request.name, category = request.category, iconKey = request.iconKey ) return roomAmenityRepo.save(amenity).toResponse() } @PutMapping("/{amenityId}") fun updateAmenity( @PathVariable amenityId: UUID, @AuthenticationPrincipal principal: MyPrincipal?, @RequestBody request: AmenityUpsertRequest ): AmenityResponse { requireSuperAdmin(principal) val amenity = roomAmenityRepo.findById(amenityId).orElse(null) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Amenity not found") if (roomAmenityRepo.existsByNameAndIdNot(request.name, amenityId)) { throw ResponseStatusException(HttpStatus.CONFLICT, "Amenity already exists") } amenity.name = request.name amenity.category = request.category ?: amenity.category amenity.iconKey = request.iconKey ?: amenity.iconKey return roomAmenityRepo.save(amenity).toResponse() } @DeleteMapping("/{amenityId}") @ResponseStatus(HttpStatus.NO_CONTENT) fun deleteAmenity( @PathVariable amenityId: UUID, @AuthenticationPrincipal principal: MyPrincipal? ) { requireSuperAdmin(principal) val amenity = roomAmenityRepo.findById(amenityId).orElse(null) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Amenity not found") if (roomTypeRepo.existsByAmenitiesId(amenityId)) { throw ResponseStatusException(HttpStatus.CONFLICT, "Amenity is used by room types") } roomAmenityRepo.delete(amenity) } private fun requirePrincipal(principal: MyPrincipal?) { if (principal == null) { throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Missing principal") } } private fun requireSuperAdmin(principal: MyPrincipal?) { if (principal == null) { throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Missing principal") } val user = appUserRepo.findById(principal.userId).orElseThrow { ResponseStatusException(HttpStatus.UNAUTHORIZED, "User not found") } if (!user.superAdmin) { throw ResponseStatusException(HttpStatus.FORBIDDEN, "Super admin only") } } } private fun RoomAmenity.toResponse(): AmenityResponse { val id = id ?: throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Amenity id missing") return AmenityResponse( id = id, name = name, category = category, iconKey = iconKey ) }