DeclaredProgramServiceImpl.java

package fr.avenirsesr.portfolio.student.progress.declared.program.domain.service;

import static fr.avenirsesr.portfolio.common.validation.domain.constraints.FieldMaxLengths.*;
import static fr.avenirsesr.portfolio.common.validation.domain.utils.FieldValidationUtils.*;

import fr.avenirsesr.portfolio.common.data.domain.model.PageCriteria;
import fr.avenirsesr.portfolio.common.data.domain.model.PagedResult;
import fr.avenirsesr.portfolio.common.security.domain.exception.UserNotAuthorizedException;
import fr.avenirsesr.portfolio.shared.domain.port.input.LoggedInUserService;
import fr.avenirsesr.portfolio.student.progress.declared.program.domain.exception.DeclaredProgramNotFoundException;
import fr.avenirsesr.portfolio.student.progress.declared.program.domain.model.DeclaredProgram;
import fr.avenirsesr.portfolio.student.progress.declared.program.domain.model.enums.EPeriodStatus;
import fr.avenirsesr.portfolio.student.progress.declared.program.domain.model.enums.EProgramStatus;
import fr.avenirsesr.portfolio.student.progress.declared.program.domain.port.input.DeclaredProgramService;
import fr.avenirsesr.portfolio.student.progress.declared.program.domain.port.output.DeclaredProgramRepository;
import fr.avenirsesr.portfolio.user.domain.model.Student;
import fr.avenirsesr.portfolio.user.domain.port.output.repository.StudentRepository;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@AllArgsConstructor
public class DeclaredProgramServiceImpl implements DeclaredProgramService {
  private final StudentRepository studentRepository;
  private final DeclaredProgramRepository declaredProgramRepository;
  private final LoggedInUserService loggedInUserService;

  private DeclaredProgram create(
      Student student,
      EProgramStatus status,
      String title,
      String description,
      String organization,
      String result,
      String sourceOfInformation,
      String link,
      LocalDate startDate,
      LocalDate endDate) {

    fieldsValidation(
        title, description, organization, result, sourceOfInformation, link, startDate, endDate);

    DeclaredProgram declaredProgram =
        DeclaredProgram.create(
            student,
            status,
            title,
            description,
            organization,
            result,
            sourceOfInformation,
            link,
            startDate,
            endDate);

    return declaredProgramRepository.save(declaredProgram);
  }

  private static void fieldsValidation(
      String title,
      String description,
      String organization,
      String result,
      String sourceOfInformation,
      String link,
      LocalDate startDate,
      LocalDate endDate) {
    requireNotBlankAndMaxLength("title", title, TITLE_LENGTH);
    requireNotBlankAndMaxLength("organization", organization, ORGANIZATION_LENGTH);
    validateOptionalTextMaxLength("description", description, DESCRIPTION_LENGTH);
    validateOptionalTextMaxLength("result", result, RESULT_LENGTH);
    validateOptionalTextMaxLength(
        "sourceOfInformation", sourceOfInformation, SOURCE_OF_INFORMATION_LENGTH);
    requireNotNull("startDate", startDate);
    validateDateOrder(startDate, endDate);
    validateUrl(link);
  }

  @Override
  public DeclaredProgram create(
      UUID studentId,
      EProgramStatus status,
      String title,
      String description,
      String organization,
      String result,
      String sourceOfInformation,
      String link,
      LocalDate startDate,
      LocalDate endDate) {
    Student student =
        studentRepository.findById(studentId).orElseThrow(UserNotAuthorizedException::new);
    return create(
        student,
        status,
        title,
        description,
        organization,
        result,
        sourceOfInformation,
        link,
        startDate,
        endDate);
  }

  @Override
  public DeclaredProgram create(
      String title,
      String description,
      String organization,
      String result,
      String sourceOfInformation,
      String link,
      LocalDate startDate,
      LocalDate endDate) {
    Student student = loggedInUserService.getLoggedInStudent();
    return create(
        student,
        getProgramStatus(startDate, endDate),
        title,
        description,
        organization,
        result,
        sourceOfInformation,
        link,
        startDate,
        endDate);
  }

  @Override
  public DeclaredProgram getById(UUID declaredProgramId) {
    DeclaredProgram declaredProgram =
        declaredProgramRepository
            .findById(declaredProgramId)
            .orElseThrow(DeclaredProgramNotFoundException::new);
    Student student = loggedInUserService.getLoggedInStudent();
    if (!declaredProgram.getStudent().equals(student)) {
      throw new UserNotAuthorizedException();
    }
    return declaredProgram;
  }

  @Override
  public PagedResult<DeclaredProgram> getDeclaredPrograms(PageCriteria pageCriteria) {
    Student student = loggedInUserService.getLoggedInStudent();
    return declaredProgramRepository.findAllByStudent(student, pageCriteria);
  }

  @Override
  public DeclaredProgram update(
      UUID declaredProgramId,
      String title,
      String description,
      String organization,
      String result,
      String sourceOfInformation,
      String link,
      LocalDate startDate,
      LocalDate endDate) {
    Student student = loggedInUserService.getLoggedInStudent();
    log.info("Update declaredProgramId {} by {}", declaredProgramId, student);
    DeclaredProgram declaredProgram =
        declaredProgramRepository
            .findById(declaredProgramId)
            .orElseThrow(DeclaredProgramNotFoundException::new);
    if (!declaredProgram.getStudent().equals(student)) {
      throw new UserNotAuthorizedException();
    }
    fieldsValidation(
        title, description, organization, result, sourceOfInformation, link, startDate, endDate);
    declaredProgram.setTitle(title);
    declaredProgram.setDescription(description);
    declaredProgram.setOrganization(organization);
    declaredProgram.setResult(result);
    declaredProgram.setSourceOfInformation(sourceOfInformation);
    declaredProgram.setLink(link);
    declaredProgram.setStartDate(startDate);
    declaredProgram.setEndDate(endDate);
    declaredProgram.setStatus(getProgramStatus(startDate, endDate));
    return declaredProgramRepository.save(declaredProgram);
  }

  @Override
  public void delete(List<UUID> declaredProgramIds) {
    Student student = loggedInUserService.getLoggedInStudent();
    List<DeclaredProgram> declaredPrograms =
        declaredProgramRepository.findAllById(declaredProgramIds);

    if (!declaredPrograms.stream().allMatch(p -> p.getStudent().equals(student))) {
      throw new UserNotAuthorizedException();
    }
    declaredProgramRepository.removeAllFromDatabase(declaredPrograms);
  }

  private EProgramStatus getProgramStatus(LocalDate startDate, LocalDate endDate) {
    EPeriodStatus periodStatus = EPeriodStatus.of(startDate, endDate);
    return switch (periodStatus) {
      case EPeriodStatus.BEFORE -> EProgramStatus.NOT_STARTED;
      case EPeriodStatus.DURING -> EProgramStatus.IN_PROGRESS;
      case EPeriodStatus.AFTER -> EProgramStatus.COMPLETED;
    };
  }
}