package dst.ass2.service.api.courseplan;

/**
 * Manages {@link CoursePlan} instances. Note that {@link CoursePlan}s are transient entities and do not have to be
 * persisted. They can be kept in memory for the duration of the application session.
 */
public interface ICoursePlanService {

    /**
     * Creates a new course plan for the participant of the given membership relation. The service is responsible for
     * assigning a unique CoursePlan ID in a thread-safe way.
     *
     * @param membershipId the membership id
     * @return a new course plan object
     * @throws EntityNotFoundException if the membership does not exist
     */
    CoursePlan create(Long membershipId) throws EntityNotFoundException;

    /**
     * Removes the CoursePlan with the given id.
     *
     * @param coursePlanId the course plan id
     * @throws EntityNotFoundException if the course plan does not exist
     */
    void delete(Long coursePlanId) throws EntityNotFoundException;

    /**
     * Finds the CoursePlan with the given id.
     *
     * @param coursePlanId the course plan id
     * @return the course plan instance, or null if it does not exist
     */
    CoursePlan find(Long coursePlanId);

    /**
     * Adds the given course to the given course plan if possible (i.e., if the owner of the course plan is eligible to
     * enroll in the course, and the course has sufficient capacity). Does nothing if the course is already in the
     * course plan.
     *
     * @param courseId the id of the course to add
     * @return true if the course was added, false if the course was already in the course plan
     * @throws EntityNotFoundException if a referenced membership or course could not be found
     * @throws CourseNotAvailableException if the course doesn't exist or can't be enrolled (e.g., no premium membership
     * or not enough capacity)
     */
    boolean addCourse(CoursePlan plan, Long courseId) throws EntityNotFoundException, CourseNotAvailableException;

    /**
     * Removes the given course from the given course plan.
     *
     * @param plan course plan to remove the course from
     * @param courseId the id of the course to remove
     * @return true if the course was removed, false if the course was not contained in the course plan
     */
    boolean removeCourse(CoursePlan plan, Long courseId);

    /**
     * Submits the given course plan by attempting to enroll the owner of the course plan into each course in the plan.
     * This method should create and persist the necessary {@code IEnrollment} objects in an atomic way, i.e., only if
     * all courses can be enrolled. Otherwise a given transaction should be rolled back. If the commit was successful,
     * the course plan should be removed from the in-memory storage.
     *
     * @throws CourseNotAvailableException if the course plan couldn't be submitted (e.g., because a course enrollment
     * couldn't be finalized because the capacity changed)
     * @throws EntityNotFoundException if a referenced membership or course could not be found
     */
    void commit(CoursePlan coursePlan) throws EntityNotFoundException, CourseNotAvailableException;
}
