package com.snp.batch.service; import com.snp.batch.global.dto.BypassConfigRequest; import com.snp.batch.global.dto.BypassConfigResponse; import com.snp.batch.global.dto.BypassParamDto; import com.snp.batch.global.model.BypassApiConfig; import com.snp.batch.global.model.BypassApiParam; import com.snp.batch.global.repository.BypassApiConfigRepository; import jakarta.persistence.EntityManager; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.List; /** * BYPASS API 설정 CRUD 비즈니스 로직 */ @Slf4j @Service @RequiredArgsConstructor public class BypassConfigService { private final BypassApiConfigRepository configRepository; private final EntityManager entityManager; /** * 설정 목록 조회 */ public List getConfigs() { return configRepository.findAll().stream() .map(this::toResponse) .toList(); } /** * 설정 상세 조회 */ public BypassConfigResponse getConfig(Long id) { BypassApiConfig config = configRepository.findById(id) .orElseThrow(() -> new IllegalArgumentException("설정을 찾을 수 없습니다: " + id)); return toResponse(config); } /** * 설정 등록 */ @Transactional public BypassConfigResponse createConfig(BypassConfigRequest request) { String endpointName = extractEndpointName(request.getExternalPath()); if (configRepository.existsByDomainNameAndEndpointName(request.getDomainName(), endpointName)) { throw new IllegalArgumentException( "이미 존재하는 도메인+엔드포인트 조합입니다: " + request.getDomainName() + "/" + endpointName); } BypassApiConfig config = toEntity(request); if (request.getParams() != null) { request.getParams().forEach(p -> { BypassApiParam param = toParamEntity(p); param.setConfig(config); config.getParams().add(param); }); } return toResponse(configRepository.save(config)); } /** * 설정 수정 */ @Transactional public BypassConfigResponse updateConfig(Long id, BypassConfigRequest request) { BypassApiConfig config = configRepository.findById(id) .orElseThrow(() -> new IllegalArgumentException("설정을 찾을 수 없습니다: " + id)); config.setDomainName(request.getDomainName()); config.setDisplayName(request.getDisplayName()); config.setWebclientBean(request.getWebclientBean()); config.setExternalPath(request.getExternalPath()); config.setHttpMethod(request.getHttpMethod()); config.setDescription(request.getDescription()); // params 교체: clear → flush(DELETE 실행) → 새로 추가 config.getParams().clear(); entityManager.flush(); if (request.getParams() != null) { request.getParams().forEach(p -> { BypassApiParam param = toParamEntity(p); param.setConfig(config); config.getParams().add(param); }); } return toResponse(configRepository.save(config)); } /** * 설정 삭제 */ @Transactional public void deleteConfig(Long id) { if (!configRepository.existsById(id)) { throw new IllegalArgumentException("설정을 찾을 수 없습니다: " + id); } configRepository.deleteById(id); } /** * 코드 생성 완료 마킹 */ @Transactional public void markAsGenerated(Long id) { BypassApiConfig config = configRepository.findById(id) .orElseThrow(() -> new IllegalArgumentException("설정을 찾을 수 없습니다: " + id)); config.setGenerated(true); config.setGeneratedAt(LocalDateTime.now()); configRepository.save(config); } // ---- private 헬퍼 메서드 ---- private BypassConfigResponse toResponse(BypassApiConfig config) { return BypassConfigResponse.builder() .id(config.getId()) .domainName(config.getDomainName()) .endpointName(config.getEndpointName()) .displayName(config.getDisplayName()) .webclientBean(config.getWebclientBean()) .externalPath(config.getExternalPath()) .httpMethod(config.getHttpMethod()) .description(config.getDescription()) .generated(config.getGenerated()) .generatedAt(config.getGeneratedAt()) .createdAt(config.getCreatedAt()) .updatedAt(config.getUpdatedAt()) .params(config.getParams().stream().map(this::toParamDto).toList()) .build(); } private BypassApiConfig toEntity(BypassConfigRequest request) { return BypassApiConfig.builder() .domainName(request.getDomainName()) .endpointName(extractEndpointName(request.getExternalPath())) .displayName(request.getDisplayName()) .webclientBean(request.getWebclientBean()) .externalPath(request.getExternalPath()) .httpMethod(request.getHttpMethod() != null ? request.getHttpMethod() : "GET") .description(request.getDescription()) .build(); } /** * externalPath의 마지막 세그먼트를 endpointName으로 추출 */ private String extractEndpointName(String externalPath) { if (externalPath == null || externalPath.isEmpty()) { return ""; } String[] segments = externalPath.split("/"); return segments[segments.length - 1]; } private BypassApiParam toParamEntity(BypassParamDto dto) { return BypassApiParam.builder() .paramName(dto.getParamName()) .paramType(dto.getParamType() != null ? dto.getParamType() : "STRING") .paramIn(dto.getParamIn() != null ? dto.getParamIn() : "QUERY") .required(dto.getRequired() != null ? dto.getRequired() : true) .description(dto.getDescription()) .sortOrder(dto.getSortOrder() != null ? dto.getSortOrder() : 0) .example(dto.getExample()) .build(); } private BypassParamDto toParamDto(BypassApiParam param) { return BypassParamDto.builder() .id(param.getId()) .paramName(param.getParamName()) .paramType(param.getParamType()) .paramIn(param.getParamIn()) .required(param.getRequired()) .description(param.getDescription()) .sortOrder(param.getSortOrder()) .example(param.getExample()) .build(); } }