package com.goldenchart.service; import com.goldenchart.dto.VerificationIssueDto; import com.goldenchart.entity.GcVerificationIssue; import com.goldenchart.entity.VerificationIssueStage; import com.goldenchart.repository.GcVerificationIssueRepository; import com.goldenchart.websocket.VerificationIssueEventBroker; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.IOException; import java.util.List; import java.util.Optional; @Service @RequiredArgsConstructor @Slf4j public class VerificationIssueService { private final GcVerificationIssueRepository repository; private final VerificationIssueImageService imageService; private final VerificationIssueEventBroker eventBroker; public List list(VerificationIssueStage stage) { List entities = stage != null ? repository.findByStageOrderByUpdatedAtDesc(stage) : repository.findAllByOrderByUpdatedAtDesc(); return entities.stream().map(this::toDto).toList(); } public Optional findById(Long id) { return repository.findById(id).map(this::toDto); } @Transactional public VerificationIssueDto save(VerificationIssueDto dto, Long userId, String deviceId) { GcVerificationIssue entity; boolean isNew = dto.getId() == null; VerificationIssueStage previousStage = null; if (dto.getId() != null) { entity = repository.findById(dto.getId()).orElseGet(GcVerificationIssue::new); if (entity.getId() != null) { previousStage = entity.getStage(); } } else { entity = new GcVerificationIssue(); entity.setUserId(userId); entity.setDeviceId(deviceId); } entity.setTitle(dto.getTitle() != null ? dto.getTitle().trim() : "제목 없음"); entity.setContent(dto.getContent() != null ? dto.getContent() : ""); String path = dto.getReproductionPath(); entity.setReproductionPath(path != null && !path.isBlank() ? path.trim() : null); entity.setStage(dto.getStage() != null ? dto.getStage() : VerificationIssueStage.REGISTERED); GcVerificationIssue saved = repository.save(entity); VerificationIssueDto result = toDto(saved); if (isNew) { eventBroker.publishCreated(result, deviceId); } else if (previousStage != null && previousStage != saved.getStage()) { eventBroker.publishStageChanged(result, previousStage, deviceId); } return result; } @Transactional public void delete(Long id) { try { imageService.deleteAllForIssue(id); } catch (IOException e) { log.warn("issue image cleanup failed id={}: {}", id, e.getMessage()); } repository.deleteById(id); } private VerificationIssueDto toDto(GcVerificationIssue e) { return VerificationIssueDto.builder() .id(e.getId()) .title(e.getTitle()) .content(e.getContent()) .reproductionPath(e.getReproductionPath()) .stage(e.getStage()) .createdAt(e.getCreatedAt()) .updatedAt(e.getUpdatedAt()) .build(); } }