Загрузка данных


package com.efs.generator.model;

public class CsvRow {
    private String operationId;
    private String fullUri;
    private String method;
    private int intensity;
    private int sla;
    private String operationId2;
    private String requirement;
    private String comment;

    public CsvRow(String operationId, String fullUri, String method, int intensity, int sla,
                  String operationId2, String requirement, String comment) {
        this.operationId = operationId;
        this.fullUri = fullUri;
        this.method = method;
        this.intensity = intensity;
        this.sla = sla;
        this.operationId2 = operationId2;
        this.requirement = requirement;
        this.comment = comment;
    }

    // Getters (if needed elsewhere)
    public String getOperationId() {
        return operationId;
    }

    public String getFullUri() {
        return fullUri;
    }

    public String getMethod() {
        return method;
    }

    public int getIntensity() {
        return intensity;
    }

    public int getSla() {
        return sla;
    }

    public String getOperationId2() {
        return operationId2;
    }

    public String getRequirement() {
        return requirement;
    }

    public String getComment() {
        return comment;
    }
}



package com.efs.generator.model;

public class LastProfileData {
    private int sla;

    public LastProfileData() {
    }

    public LastProfileData(int sla) {
        this.sla = sla;
    }

    public int getSla() {
        return sla;
    }

    public void setSla(int sla) {
        this.sla = sla;
    }
}


package com.efs.generator.model;

public class ProfileEntry {
    private String method;
    private String uri;
    private int intensity;

    public ProfileEntry() {
    }

    public ProfileEntry(String method, String uri, int intensity) {
        this.method = method;
        this.uri = uri;
        this.intensity = intensity;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }

    public int getIntensity() {
        return intensity;
    }

    public void setIntensity(int intensity) {
        this.intensity = intensity;
    }
}

package com.efs.generator.util;

/**
 * Utility class for extracting HTTP method from operation ID.
 */
public class MethodExtractor {

    /**
     * Extracts the HTTP method from an operation ID string.
     * Expected format: UCxxx_METHOD_REST... (e.g., UC114_POST_business_analytics_industry_top_avgcheck_WEB)
     *
     * @param opId operation ID string
     * @return HTTP method (e.g., "POST", "GET") or empty string if not found
     */
    public String extractMethodFromOperationId(String opId) {
        if (opId == null || opId.isEmpty()) {
            return "";
        }
        String[] parts = opId.split("_");
        if (parts.length >= 3) {
            // parts[0] = UCxxx, parts[1] = method, rest = rest
            return parts[1];
        }
        return "";
    }
}


package com.efs.generator.util;

/**
 * Utility class for normalizing URIs based on project type.
 */
public class UriNormalizer {

    /**
     * Normalizes the given URI according to the project type.
     * <p>
     * The actual implementation should mirror the logic used in {@link CsvGeneratorService}
     * for building the fullUri.
     *
     * @param uri       the original URI from the profile
     * @param projectType the project type (e.g., "WEB", "MOBILE", "PPRB")
     * @return normalized URI
     */
    public String normalizeUri(String uri, String projectType) {
        if (uri == null) {
            return null;
        }
        // Placeholder implementation; the real logic is in CsvGeneratorService
        // This method should be implemented to match the URI normalization rules.
        return uri;
    }
}

package com.efs.generator;

import java.util;

import java.util.*;
import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.efs.generator.model.ProfileEntry;
import com.efs.generator.model.LastProfileData;
import com.efs.generator.model.CsvRow;
import com.efs.generator.util.UriNormalizer;
import com.efs.generator.util.MethodExtractor;


@Service
public class CsvGeneratorService {

    private static final Logger log = LoggerFactory.getLogger(CsvGeneratorService.class);
    private static final int DEFAULT_SLA = 0;

    private final UriNormalizer uriNormalizer;
    private final MethodExtractor methodExtractor;

    public CsvGeneratorService(UriNormalizer uriNormalizer, MethodExtractor methodExtractor) {
        this.uriNormalizer = uriNormalizer;
        this.methodExtractor = methodExtractor;
    }

    public void generateProfile(List<ProfileEntry> scriptEntries,
                                List<ProfileEntry> profileEntries,
                                String projectType,
                                String urlPrefix,
                                String requirement,
                                Map<String, LastProfileData> lastProfileData,
                                List<CsvRow> allRowsForExcel) {
        Map<String, List<String>> normalizedUrlToOpIds = new HashMap<>();
        Set<String> matchedOpIds = new HashSet<>();
        Set<String> usedOpIds = new HashSet<>();
        int matchedCount = 0;
        int newCount = 0;
        int nextUcNum = 1;
        int validProfileEntriesCount = 0;

        // Build normalized URL -> operation IDs map from script entries
        for (ProfileEntry entry : scriptEntries) {
            String normalizedUri = uriNormalizer.normalizeUri(entry.getUri(), projectType);
            List<String> opIds = normalizedUrlToOpIds.computeIfAbsent(normalizedUri, k -> new ArrayList<>());
            String opId = generateNewOperationId(entry, usedOpIds, nextUcNum);
            opIds.add(opId);
            usedOpIds.add(opId);
            nextUcNum = extractUcNumber(opId) + 1;
        }

        log.debug("--- Обработка операций из профиля аналитика ---");

        for (ProfileEntry entry : profileEntries) {
            log.debug("  Обработка entry: метод={}, uri={}, интенсивность={}", entry.getMethod(), entry.getUri(), entry.getIntensity());

            if (entry.getIntensity() > 0) {
                validProfileEntriesCount++;
            } else {
                log.info("   Операция с нулевой интенсивностью: {} {} - будет покрашена красным в Excel",
                        entry.getMethod(), entry.getUri());
            }

            String operationId = null;
            String profileMethod = entry.getMethod();

            String normalizedUri = uriNormalizer.normalizeUri(entry.getUri(), projectType);

            if (normalizedUrlToOpIds.containsKey(normalizedUri)) {
                List<String> opIds = normalizedUrlToOpIds.get(normalizedUri);

                for (String opId : opIds) {
                    if (!matchedOpIds.contains(opId)) {
                        String opMethod = extractMethodFromOperationId(opId);
                        if (opMethod.equals(profileMethod)) {
                            operationId = opId;
                            matchedOpIds.add(opId);
                            break;
                        }
                    }
                }

                if (operationId == null) {
                    for (String opId : opIds) {
                        if (!matchedOpIds.contains(opId)) {
                            operationId = opId;
                            matchedOpIds.add(opId);
                            if (entry.getIntensity() > 0) {
                                log.warn("   Метод не совпадает! Профиль: {}, operationId: {} (URI: {})",
                                        profileMethod, opId, entry.getUri());
                            }
                            break;
                        }
                    }
                }

                if (operationId != null) {
                    if (entry.getIntensity() > 0) {
                        if (opIds.size() > 1) {
                            log.debug("   Найден в скрипте (один из {}): {} {} → {} (инт: {})",
                                    opIds.size(), profileMethod, entry.getUri(), operationId, entry.getIntensity());
                        } else {
                            log.debug("  Найден в скрипте: {} {} → {} (инт: {})",
                                    profileMethod, entry.getUri(), operationId, entry.getIntensity());
                        }
                        matchedCount++;
                    }
                } else {
                    if (entry.getIntensity() > 0) {
                        log.warn("   Все operation_id для URI {} уже использованы. Создаём новый.", entry.getUri());
                    }
                    operationId = generateNewOperationId(entry, usedOpIds, nextUcNum);
                    nextUcNum = extractUcNumber(operationId) + 1;
                    usedOpIds.add(operationId);
                    if (entry.getIntensity() > 0) {
                        newCount++;
                    }
                }
            } else {
                operationId = generateNewOperationId(entry, usedOpIds, nextUcNum);
                nextUcNum = extractUcNumber(operationId) + 1;
                usedOpIds.add(operationId);
                if (entry.getIntensity() > 0) {
                    log.info("   Создан новый: {} {} → {} (инт: {})",
                            profileMethod, entry.getUri(), operationId, entry.getIntensity());
                    newCount++;
                } else {
                    log.info("   Создан ID для нулевой операции: {} {} → {} (инт: 0)",
                            profileMethod, entry.getUri(), operationId);
                }
            }

            int sla = DEFAULT_SLA;
            if (lastProfileData.containsKey(operationId)) {
                sla = lastProfileData.get(operationId).getSla();
            }

            String fullUri;
            String uriFromProfile = entry.getUri();

            if ("PPRB".equals(projectType)) {
                // Для PPRB не добавляем префикс и не меняем URI
                fullUri = uriFromProfile;
            } else if (uriFromProfile.startsWith("/ic/ufs/corp-retail/")) {
                // Для WEB: уже содержит префикс, не добавляем urlPrefix
                fullUri = uriFromProfile;
            } else if (uriFromProfile.startsWith("/ic/ufs/mobile/")) {
                // Убираем ведущий "/ic" для мобильного пути
                String withoutIC = uriFromProfile.substring(3); // remove leading "/ic"
                // После удаления, строка начинается с "/ufs/mobile/..."
                if (withoutIC.startsWith("/ufs/mobile/")) {
                    // Уже содержит базовый путь, не добавляем urlPrefix
                    fullUri = withoutIC;
                } else {
                    // На всякий случай, если после удаления не совпадает (не должно случиться)
                    fullUri = urlPrefix + withoutIC;
                }
            } else if (uriFromProfile.startsWith("/ufs/mobile/")) {
                // Для мобильного: уже содержит базовый путь
                fullUri = uriFromProfile;
            } else if (uriFromProfile.startsWith("/")) {
                // Относительный путь к корню сайта
                fullUri = urlPrefix + uriFromProfile;
            } else {
                // Относительный путь без ведущего слеша
                fullUri = urlPrefix + "/" + uriFromProfile;
            }

            CsvRow row = new CsvRow(
                    operationId,
                    fullUri,
                    entry.getMethod(),
                    entry.getIntensity(),  // может быть 0
                    sla,
                    operationId,
                    requirement,
                    ""
            );

            // ИЗМЕНЕНО: добавляем ВСЕ операции в список для Excel
            allRowsForExcel.add(row);
        }

        log.debug("--- Итого ---");
        log.debug("  Скрипт операций: {}", scriptEntries.size());
        log.debug("  Профиль аналитика: {}", profileEntries.size());
        log.debug("  Сопоставлено: {}", matchedCount);
        log.debug("  Новых: {}", newCount);
        log.debug("  Всего в результирующем профиле: {}", (matchedCount + newCount));
    }

    private String generateNewOperationId(ProfileEntry entry, Set<String> usedOpIds, int nextUcNum) {
        String base = "UC" + String.format("%03d", nextUcNum) + "_" + entry.getMethod() + "_" + entry.getUri().replaceAll("[^a-zA-Z0-9]", "_").toUpperCase();
        String opId = base;
        int counter = 0;
        while (usedOpIds.contains(opId)) {
            counter++;
            opId = base + "_" + counter;
        }
        return opId;
    }

    private String extractMethodFromOperationId(String opId) {
        // Example: UC114_POST_business_analytics_industry_top_avgcheck_WEB
        // We need to extract the method part between first and second underscore after UCxxx_
        // Format: UCxxx_METHOD_REST
        // We'll split by '_'
        String[] parts = opId.split("_");
        if (parts.length >= 3) {
            // parts[0] = UCxxx, parts[1] = method, rest = rest
            return parts[1];
        }
        // fallback: return empty
        return "";
    }

    private int extractUcNumber(String opId) {
        // Extract the numeric part after UC
        // opId format: UCxxx_...
        if (opId.startsWith("UC") && opId.length() >= 5) {
            String numPart = opId.substring(2, 5); // assuming three digits
            try {
                return Integer.parseInt(numPart);
            } catch (NumberFormatException e) {
                return 0;
            }
        }
        return 0;
    }
}