package ru.soune.nocopy.service.complaint; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ru.soune.nocopy.dto.complaint.ComplaintRequest; import ru.soune.nocopy.dto.complaint.ComplaintResponse; import ru.soune.nocopy.entity.complaint.ComplaintEntity; import ru.soune.nocopy.entity.complaint.ComplaintStatus; import ru.soune.nocopy.entity.file.FileStatus; import ru.soune.nocopy.entity.notification.NotificationType; import ru.soune.nocopy.entity.violation.Violation; import ru.soune.nocopy.exception.ComplaintNotFoundException; import ru.soune.nocopy.exception.DuplicateComplaintException; import ru.soune.nocopy.exception.ViolationNotFoundException; import ru.soune.nocopy.repository.ComplaintEntityRepository; import ru.soune.nocopy.repository.ViolationRepository; import ru.soune.nocopy.service.notification.NotificationService; import ru.soune.nocopy.service.violation.ViolationService; import ru.soune.nocopy.service.violation.ViolationStatus; import java.time.format.DateTimeFormatter; import java.util.List; @Slf4j @Service @RequiredArgsConstructor @Transactional public class ComplaintEntityService { private final ComplaintEntityRepository complaintRepository; private final ViolationRepository violationRepository; private final ViolationService violationService; private final NotificationService notificationService; private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); public ComplaintResponse createComplaint(ComplaintRequest request) { Violation violation = violationRepository.findById(request.getViolationId()) .orElseThrow(() -> new ViolationNotFoundException("Violation not found: " + request.getViolationId())); if (complaintRepository.existsByViolationId(request.getViolationId())) { throw new DuplicateComplaintException("Complaint already exists for violation: " + request.getViolationId()); } ComplaintEntity complaint = ComplaintEntity.builder() .status(ComplaintStatus.CREATED) .complaintText(request.getComplaintText()) .email(request.getEmail()) .violation(violation) .not_moderated_file(violation.getFileEntity().getStatus().equals(FileStatus.MODERATION)) .build(); violationService.changeStatus(ViolationStatus.COMPLAINT_IN_WORK, request.getViolationId()); return mapToResponse(complaintRepository.save(complaint)); } @Transactional(readOnly = true) public Page getAllComplaintsByEmail(Pageable pageable, List emails) { return complaintRepository.getComplaintsByUserEmails(emails, pageable) .map(this::mapToResponse); } @Transactional(readOnly = true) public ComplaintResponse getComplaintById(Long id) { return complaintRepository.findById(id) .map(this::mapToResponse) .orElseThrow(() -> new ComplaintNotFoundException("Complaint not found: " + id)); } @Transactional(readOnly = true) public Page getAllComplaints(Pageable pageable) { return complaintRepository.findAll(pageable).map(this::mapToResponse); } @Transactional(readOnly = true) public ComplaintResponse getComplaintsByViolationId(Long violationId) { if (!violationRepository.existsById(violationId)) { throw new ViolationNotFoundException("Violation not found: " + violationId); } return mapToResponse(complaintRepository.findByViolationId(violationId)); } public List fetchComplaintByViolation(Long violationId) { if (!violationRepository.existsById(violationId)) { return null; } return complaintRepository.findByViolationIdAndStatuses(violationId, List.of(ComplaintStatus.CREATED.name(), ComplaintStatus.SHOWED.name(), ComplaintStatus.IN_WORK.name())); } public ComplaintResponse updateComplaintStatus(ComplaintEntity complaint, ComplaintStatus status) { complaint.setStatus(status); return mapToResponse(complaintRepository.save(complaint)); } public ComplaintResponse updateComplaint(Long id, ComplaintRequest request) { ComplaintEntity complaint = complaintRepository.findById(id) .orElseThrow(() -> new ComplaintNotFoundException("Complaint not found: " + id)); if (request.getViolationId() != null) { Violation violation = violationRepository.findById(request.getViolationId()) .orElseThrow(() -> new ViolationNotFoundException("Violation not found: " + request.getViolationId())); complaint.setViolation(violation); } if (request.getComplaintText() != null) complaint.setComplaintText(request.getComplaintText()); if (request.getEmail() != null) complaint.setEmail(request.getEmail()); if (request.getStatus() != null) { complaint.setStatus(ComplaintStatus.valueOf(request.getStatus())); notificationService.addNotification(NotificationType.COMPLAINT_STATUS_CHANGED, complaint.getViolation() .getFileEntity().getUserId(), request.getStatus()); } return mapToResponse(complaintRepository.save(complaint)); } public ComplaintResponse deleteComplaint(Long id) { ComplaintEntity complaint = complaintRepository.findById(id) .orElseThrow(() -> new ComplaintNotFoundException("Complaint not found: " + id)); complaint.setStatus(ComplaintStatus.CANCELLED); return mapToResponse(complaintRepository.save(complaint)); } private ComplaintResponse mapToResponse(ComplaintEntity entity) { Violation violation = entity.getViolation(); return ComplaintResponse.builder() .id(entity.getId()) .status(entity.getStatus() != null ? entity.getStatus().name() : null) .complaintText(entity.getComplaintText()) .email(entity.getEmail()) .violationId(violation != null ? violation.getId() : null) .fileId(violation != null ? violation.getFileEntity().getId() : null) .createdAt(entity.getCreatedAt() != null ? entity.getCreatedAt().format(DATE_FORMATTER) : null) .updatedAt(entity.getUpdatedAt() != null ? entity.getUpdatedAt().format(DATE_FORMATTER) : null) .notModerated(entity.getNot_moderated_file() != null ? entity.getNot_moderated_file() : null) .build(); } }