package de.rwth.idsg.bikeman.app.service;
import de.rwth.idsg.bikeman.app.dto.ViewBookingDTO;
import de.rwth.idsg.bikeman.app.dto.ViewPedelecSlotDTO;
import de.rwth.idsg.bikeman.app.exception.AppErrorCode;
import de.rwth.idsg.bikeman.app.exception.AppException;
import de.rwth.idsg.bikeman.domain.Booking;
import de.rwth.idsg.bikeman.domain.Customer;
import de.rwth.idsg.bikeman.domain.Pedelec;
import de.rwth.idsg.bikeman.domain.Reservation;
import de.rwth.idsg.bikeman.ixsi.IxsiCodeException;
import de.rwth.idsg.bikeman.ixsi.IxsiProcessingException;
import de.rwth.idsg.bikeman.ixsi.service.AvailabilityPushService;
import de.rwth.idsg.bikeman.ixsi.service.BookingCheckService;
import de.rwth.idsg.bikeman.ixsi.service.BookingService;
import de.rwth.idsg.bikeman.psinterface.dto.request.CancelReservationDTO;
import de.rwth.idsg.bikeman.psinterface.dto.request.ReserveNowDTO;
import de.rwth.idsg.bikeman.psinterface.rest.client.StationClient;
import de.rwth.idsg.bikeman.repository.BookingRepository;
import de.rwth.idsg.bikeman.repository.ReservationRepository;
import de.rwth.idsg.bikeman.web.rest.exception.DatabaseException;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xjc.schema.ixsi.TimePeriodProposalType;
import xjc.schema.ixsi.TimePeriodType;
import java.util.List;
import java.util.Optional;
@Service
@Slf4j
public class AppBookingService {
@Autowired private AppPedelecService appPedelecService;
@Autowired private BookingRepository bookingRepository;
@Autowired private BookingService bookingService;
@Autowired private ReservationRepository reservationRepository;
@Autowired private StationClient stationClient;
@Autowired private AvailabilityPushService availabilityPushService;
@Autowired private BookingCheckService bookingCheckService;
@Transactional
public Optional<ViewBookingDTO> createBooking(Long stationId, Customer customer) {
try {
TimePeriodProposalType timePeriodProposal = new TimePeriodProposalType()
.withBegin(new DateTime())
.withEnd(new DateTime().plusMinutes(15));
Optional<Pedelec> optionalPedelec = appPedelecService.getRecommendedPedelecForBooking(stationId);
if (!optionalPedelec.isPresent()) {
return Optional.empty();
}
Pedelec pedelec = optionalPedelec.get();
Booking createdBooking = bookingService.createBookingForUser(
pedelec.getManufacturerId(),
customer.getCardAccount().getCardId(),
timePeriodProposal
);
TimePeriodType timePeriod = new TimePeriodType()
.withBegin(createdBooking.getReservation().getStartDateTime().toDateTime())
.withEnd(createdBooking.getReservation().getEndDateTime().toDateTime());
String placeId = createdBooking.getReservation()
.getPedelec()
.getStationSlot()
.getStation()
.getManufacturerId();
availabilityPushService.placedBooking(pedelec.getManufacturerId(), placeId, timePeriod);
bookingCheckService.placedBooking(createdBooking);
ViewBookingDTO viewBookingDTO = ViewBookingDTO.builder()
.expiryDateTime(new LocalDateTime(timePeriod.getEnd()))
.stationSlotPosition(pedelec.getStationSlot().getStationSlotPosition())
.stationId(stationId)
.build();
return Optional.of(viewBookingDTO);
} catch (IxsiCodeException e) {
return Optional.empty();
} catch (IxsiProcessingException e) {
return Optional.empty();
} catch (Exception e) {
return Optional.empty();
}
}
@Transactional(readOnly = true)
public Optional<ViewBookingDTO> getDTO(Customer customer) {
Optional<Reservation> optional = this.getReservation(customer);
if (!optional.isPresent()) {
return Optional.empty();
}
return Optional.of(
ViewBookingDTO.builder()
.stationId(optional.get().getPedelec().getStationSlot().getStation().getStationId())
.stationSlotPosition(optional.get().getPedelec().getStationSlot().getStationSlotPosition())
.expiryDateTime(optional.get().getEndDateTime())
.build()
);
}
@Transactional(readOnly = true)
public Optional<ViewPedelecSlotDTO> getSlot(Customer customer) {
Optional<Reservation> optional = this.getReservation(customer);
if (!optional.isPresent()) {
return Optional.empty();
}
return Optional.of(
ViewPedelecSlotDTO.builder()
.stationSlotId(optional.get().getPedelec().getStationSlot().getStationSlotId())
.stationSlotPosition(optional.get().getPedelec().getStationSlot().getStationSlotPosition())
.build()
);
}
@Transactional(readOnly = true)
public Optional<Long> getBookingSlotId(Customer customer) {
Optional<Reservation> optional = this.getReservation(customer);
if (!optional.isPresent()) {
return Optional.empty();
}
return Optional.of(optional.get().getPedelec().getStationSlot().getStationSlotId());
}
@Transactional
public void delete(Customer customer) {
Optional<Reservation> optional = this.getReservation(customer);
if (!optional.isPresent()) {
throw new AppException("No valid Reservation found!", AppErrorCode.CONSTRAINT_FAILED);
}
Reservation reservation = optional.get();
Booking booking = bookingService.cancel(reservation.getBooking().getIxsiBookingId(), customer.getCardAccount().getCardId());
TimePeriodType timePeriod = new TimePeriodType()
.withBegin(booking.getReservation().getStartDateTime().toDateTime())
.withEnd(booking.getReservation().getEndDateTime().toDateTime());
String pedelecId = booking.getReservation()
.getPedelec()
.getManufacturerId();
String placeId = booking.getReservation()
.getPedelec()
.getStationSlot()
.getStation()
.getManufacturerId();
availabilityPushService.cancelledBooking(pedelecId, placeId, timePeriod);
bookingCheckService.cancelledBooking(booking);
}
@Transactional(readOnly = true)
private Optional<Reservation> getReservation(Customer customer) {
List<Reservation> reservations = reservationRepository.findByCustomerIdAndTime(
customer.getCardAccount().getCardAccountId(),
LocalDateTime.now());
if (reservations.isEmpty()) {
return Optional.empty();
}
if (reservations.size() > 1) {
throw new AppException("More than one reservation found!", AppErrorCode.CONSTRAINT_FAILED);
}
return Optional.of(reservations.get(0));
}
}