package com.drinkool.services; import com.drinkool.InternalValue; import com.drinkool.Role; import com.drinkool.dtos.CreateShift; import com.drinkool.dtos.RegisterShift; import com.drinkool.entities.EateryEntity; import com.drinkool.entities.ShiftEntity; import com.drinkool.entities.ShiftRegistrationEntity; import io.vertx.core.http.HttpServerRequest; import jakarta.annotation.security.RolesAllowed; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.transaction.Transactional; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; import org.eclipse.microprofile.graphql.*; @GraphQLApi @ApplicationScoped public class ShiftService { @Inject HttpServerRequest request; // --- QUERIES --- @Query("allShifts") @Description("Lấy danh sách tất cả các loại ca trực") @RolesAllowed({ Role.Staff, Role.Manager }) public List getAllShifts() throws GraphQLException { String ownerId = request.getHeader(InternalValue.managerId); if (ownerId == null || ownerId.isEmpty()) { ownerId = request.getHeader(InternalValue.userId); } EateryEntity eatery = EateryEntity.findByOwnerId(ownerId); return ShiftEntity.list("eatery", eatery); } @Query("myRegistrations") @Description("Lấy danh sách ca trực mà nhân viên hiện tại đã đăng ký") @RolesAllowed(Role.Staff) public List getMyShifts() { String userId = request.getHeader(InternalValue.userId); return ShiftRegistrationEntity.list("staffId", UUID.fromString(userId)); } @Query("allRegistrations") @Description("Manager xem toàn bộ danh sách đăng ký của tất cả nhân viên") @RolesAllowed(Role.Manager) public List getAllRegistrations() { return ShiftRegistrationEntity.listAll(); } // --- MUTATIONS --- @Mutation("registerShift") @Description("Nhân viên đăng ký vào một ca trực cụ thể") @RolesAllowed(Role.Staff) @Transactional public ShiftRegistrationEntity registerShift( @Name("registration") RegisterShift registration ) throws GraphQLException { String userIdStr = request.getHeader(InternalValue.userId); String managerIdStr = request.getHeader(InternalValue.managerId); UUID staffId = UUID.fromString(userIdStr); EateryEntity eatery = EateryEntity.findByOwnerId(managerIdStr); if (eatery == null) throw new GraphQLException("NotFoundEatery"); ShiftEntity shift = ShiftEntity.find( "id = ?1 and eatery.id = ?2", registration.shiftId, eatery.id ).firstResult(); if (shift == null) throw new GraphQLException("NotFoundShift"); List overlappingShifts = ShiftRegistrationEntity.findOverlappingShifts(staffId, shift); if (!overlappingShifts.isEmpty()) { String ids = overlappingShifts .stream() .map(reg -> reg.shift.id.toString()) .distinct() .collect(Collectors.joining(", ")); throw new GraphQLException("OverlappingShift: " + ids); } long currentStaffCount = ShiftRegistrationEntity.countByShift(shift.id); if (shift.maxStaff != null && currentStaffCount >= shift.maxStaff) { throw new GraphQLException("FulledShift"); } ShiftRegistrationEntity record = new ShiftRegistrationEntity(); record.staffId = staffId; record.shift = shift; record.persist(); return record; } @Mutation("createShift") @Description("Quản lý tạo mới một loại ca trực") @RolesAllowed(Role.Manager) @Transactional public ShiftEntity createShift(@Name("shiftInput") CreateShift input) throws GraphQLException { String ownerId = request.getHeader(InternalValue.userId); EateryEntity eatery = EateryEntity.findByOwnerId(ownerId); if (eatery == null) return null; ShiftEntity shift = new ShiftEntity(); shift.eatery = eatery; shift.name = input.name; shift.startTime = input.startTime; shift.endTime = input.endTime; shift.maxStaff = input.maxStaff; if (shift.endTime.isBefore(shift.startTime)) { throw new GraphQLException("InvalidEndTime"); } shift.persist(); return shift; } @Mutation("updateShift") @Description("Quản lý cập nhật thông tin ca trực") @RolesAllowed(Role.Manager) @Transactional public ShiftEntity updateShift( @Name("id") UUID id, @Name("shiftInput") CreateShift input ) throws GraphQLException { ShiftEntity shift = ShiftEntity.findById(id); if (shift == null) throw new GraphQLException("NotFoundShift"); String ownerId = request.getHeader(InternalValue.userId); if ( !shift.eatery.ownerId.toString().equals(ownerId) ) throw new GraphQLException("InvalidShiftId"); shift.name = input.name; shift.startTime = input.startTime; shift.endTime = input.endTime; shift.maxStaff = input.maxStaff; if (shift.endTime.isBefore(shift.startTime)) { throw new GraphQLException("InvalidEndTime"); } return shift; } @Mutation("deleteShift") @Description("Quản lý xóa một ca trực") @RolesAllowed(Role.Manager) @Transactional public boolean deleteShift(@Name("id") UUID id) throws GraphQLException { String ownerId = request.getHeader(InternalValue.userId); EateryEntity eatery = EateryEntity.findByOwnerId(ownerId); if (eatery == null) { throw new GraphQLException("NotFoundEatery"); } ShiftEntity shift = ShiftEntity.find( "id = ?1 and eatery = ?2", id, eatery ).firstResult(); if (shift == null) { throw new GraphQLException("NotFoundShiftOrAccessDenied"); } long count = ShiftRegistrationEntity.count("shift.id", id); if (count > 0) throw new GraphQLException( "CannotDeleteShiftWithRegistrations" ); return ShiftEntity.deleteById(id); } @Mutation("cancelRegistration") @Description("Nhân viên hủy ca đã đăng ký") @RolesAllowed(Role.Staff) @Transactional public boolean cancelRegistration(@Name("registrationId") UUID id) throws GraphQLException { String userId = request.getHeader(InternalValue.userId); ShiftRegistrationEntity reg = ShiftRegistrationEntity.findById(id); if (reg == null) throw new GraphQLException("RegistrationNotFound"); if (!reg.staffId.equals(UUID.fromString(userId))) { throw new GraphQLException("NotYourRegistration"); } reg.delete(); return true; } }