package com.hitcommunications.servermanager.services; import com.hitcommunications.servermanager.mappers.ServersMapper; import com.hitcommunications.servermanager.model.Servers; import com.hitcommunications.servermanager.model.dtos.BulkServerImportResponse; import com.hitcommunications.servermanager.model.dtos.BulkServerImportResponse.FailedRow; import com.hitcommunications.servermanager.model.dtos.NewServerDTO; import com.hitcommunications.servermanager.model.dtos.ServerDTO; import com.hitcommunications.servermanager.model.enums.TypeCategory; import com.hitcommunications.servermanager.repositories.ServersRepository; import com.hitcommunications.servermanager.services.TypeOptionService; import com.hitcommunications.servermanager.utils.TypeNormalizer; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.ArrayList; import java.util.LinkedHashMap; @Service @RequiredArgsConstructor public class ServersService { private final ServersMapper mapper; private final ServersRepository repo; private final TypeOptionService typeOptionService; public ServerDTO create(NewServerDTO createDTO) { Servers entity = mapper.toEntity(createDTO); applyNormalizedTypeData(entity, createDTO); entity = repo.save(entity); return mapper.toDTO(entity); } public ServerDTO getById(String id) { return repo.findById(id) .map(mapper::toDTO) .orElseThrow(() -> new RuntimeException("Server not found with id: " + id)); } public ServerDTO getByName(String name) { return repo.findByName(name) .map(mapper::toDTO) .orElseThrow(() -> new RuntimeException("Server not found with name: " + name)); } public List getByType(String type) { String normalized = normalizeFilter(type, TypeCategory.SERVER_TYPE); return repo.findByType(normalized) .stream() .map(mapper::toDTO) .toList(); } public Map countAllByType() { Map response = new LinkedHashMap<>(); typeOptionService.list(TypeCategory.SERVER_TYPE).forEach(type -> { response.put(type, repo.countAllByType(type)); }); // Garantir que valores existentes, mas não registrados, também apareçam repo.findAll().stream() .map(Servers::getType) .filter(type -> type != null && !response.containsKey(type)) .distinct() .forEach(type -> response.put(type, repo.countAllByType(type))); return response; } public List getByApplication(String application) { String normalized = normalizeFilter(application, TypeCategory.APPLICATION); return repo.findByApplication(normalized) .stream() .map(mapper::toDTO) .toList(); } public BulkServerImportResponse bulkCreate(MultipartFile file) { List failures = new ArrayList<>(); int succeeded = 0; int processed = 0; try (BufferedReader reader = new BufferedReader(new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8))) { String line; int lineNumber = 0; while ((line = reader.readLine()) != null) { lineNumber++; if (line.isBlank()) { continue; } String[] columns = parseColumns(line); if (isHeaderRow(columns)) { continue; } processed++; try { registerTypeOptionsFromRow(columns); NewServerDTO dto = toNewServerDTO(columns); create(dto); succeeded++; } catch (Exception ex) { failures.add(new FailedRow(lineNumber, ex.getMessage(), line)); } } } catch (IOException e) { throw new RuntimeException("Erro ao ler arquivo CSV.", e); } int failed = failures.size(); return new BulkServerImportResponse(processed, succeeded, failed, failures); } private String[] parseColumns(String line) { String[] rawColumns = line.split(";"); String[] columns = new String[rawColumns.length]; for (int i = 0; i < rawColumns.length; i++) { columns[i] = rawColumns[i].trim(); } return columns; } private NewServerDTO toNewServerDTO(String[] columns) { if (columns.length < 8) { throw new IllegalArgumentException("Linha incompleta. Esperado 8 colunas."); } String name = columns[0]; String ip = columns[1]; Integer port = Integer.parseInt(columns[2]); String user = columns[3]; String password = columns[4]; String type = columns[5]; String application = columns[6]; String dbType = columns[7]; return new NewServerDTO(name, ip, port, user, password, type, application, dbType); } private void registerTypeOptionsFromRow(String[] columns) { if (columns.length < 8) { return; } registerTypeOption(TypeCategory.SERVER_TYPE, columns[5]); registerTypeOption(TypeCategory.APPLICATION, columns[6]); registerTypeOption(TypeCategory.DATABASE, columns[7]); } private void registerTypeOption(TypeCategory category, String value) { if (value == null || value.isBlank()) { return; } typeOptionService.register(category, value); } private boolean isHeaderRow(String[] columns) { if (columns.length < 8) { return false; } return "name".equalsIgnoreCase(columns[0]) && "ip".equalsIgnoreCase(columns[1]) && "port".equalsIgnoreCase(columns[2]); } public List getAll() { return repo.findAll() .stream() .map(mapper::toDTO) .toList(); } public List search(String query, String type, String application, String dbType) { String normalizedQuery = (query == null || query.isBlank()) ? null : query.trim(); String typeFilter = normalizeFilter(type, TypeCategory.SERVER_TYPE); String applicationFilter = normalizeFilter(application, TypeCategory.APPLICATION); String dbTypeFilter = normalizeFilter(dbType, TypeCategory.DATABASE); return repo.search(normalizedQuery, typeFilter, applicationFilter, dbTypeFilter) .stream() .map(mapper::toDTO) .toList(); } public ServerDTO update(String id, NewServerDTO updateDTO) { Servers entity = repo.findById(id) .orElseThrow(() -> new RuntimeException("Server not found with id: " + id)); mapper.partialUpdate(updateDTO, entity); applyNormalizedTypeData(entity, updateDTO); entity = repo.save(entity); return mapper.toDTO(entity); } public void delete(String id) { if (!repo.existsById(id)) { throw new RuntimeException("Server not found with id: " + id); } repo.deleteById(id); } private void applyNormalizedTypeData(Servers entity, NewServerDTO dto) { entity.setType(normalizeAndRegister(TypeCategory.SERVER_TYPE, dto.type())); entity.setApplication(normalizeAndRegister(TypeCategory.APPLICATION, dto.application())); entity.setDbType(normalizeAndRegister(TypeCategory.DATABASE, dto.dbType())); } private String normalizeFilter(String value, TypeCategory category) { if (value == null || value.isBlank()) { return null; } String normalized = TypeNormalizer.normalize(value); if (normalized == null) { return null; } typeOptionService.register(category, normalized); return normalized; } private String normalizeAndRegister(TypeCategory category, String value) { String normalized = TypeNormalizer.normalize(value); if (normalized == null) { throw new IllegalArgumentException("Valor inválido para " + category.name()); } typeOptionService.register(category, normalized); return normalized; } }