package com.codechecker.api.analyzer;

import com.codechecker.api.model.EndpointChangeReport;
import com.codechecker.api.model.EndpointSnapshot;
import com.codechecker.api.parser.EndpointSnapshotParser;
import com.codechecker.api.scanner.ApiFileChangeScanner;
import com.codechecker.config.AppConfig;
import com.codechecker.git.GitChangeScanner;

import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

/**
 * API 变更分析编排（与 {@link com.codechecker.analyzer.ClassChangeAnalyzer} 平行、互不调用）。
 */
public class ApiChangeAnalyzer {
    private final GitChangeScanner gitScanner;
    private final ApiFileChangeScanner fileScanner;

    public ApiChangeAnalyzer(GitChangeScanner gitScanner) {
        this.gitScanner = gitScanner;
        this.fileScanner = new ApiFileChangeScanner(gitScanner);
    }

    public List<EndpointChangeReport> analyze(Path repoRoot, AppConfig config,
                                              String oldSha, String newSha) throws IOException {
        List<String> changedFiles = fileScanner.scanChangedFiles(
                repoRoot, config.getAllApiScanDirs(), oldSha, newSha);
        if (changedFiles.isEmpty()) {
            return List.of();
        }

        EndpointSnapshotParser parser = new EndpointSnapshotParser(config.isApiExcludeFrameworkParams());
        ParameterDiffEngine parameterDiffEngine = new ParameterDiffEngine(
                repoRoot, buildSearchDirs(config), gitScanner, oldSha, newSha, config.getNestMaxDepth());
        EndpointDiffEngine endpointDiffEngine = new EndpointDiffEngine(parameterDiffEngine);

        List<EndpointSnapshot> oldSnapshots = new ArrayList<>();
        List<EndpointSnapshot> newSnapshots = new ArrayList<>();

        for (String path : changedFiles) {
            boolean feign = isFeignPath(path, config);
            String oldSource = gitScanner.readFileAtCommit(oldSha, path);
            String newSource = gitScanner.readFileAtCommit(newSha, path);
            oldSnapshots.addAll(parser.parseSource(oldSource, path, feign));
            newSnapshots.addAll(parser.parseSource(newSource, path, feign));
        }

        return endpointDiffEngine.diff(oldSnapshots, newSnapshots);
    }

    private List<String> buildSearchDirs(AppConfig config) {
        List<String> dirs = new ArrayList<>();
        dirs.addAll(config.getModelDirs());
        dirs.addAll(config.getAllApiScanDirs());
        return dirs;
    }

    private boolean isFeignPath(String path, AppConfig config) {
        String normalized = path.replace('\\', '/');
        for (String dir : config.getApiFeignScanDirs()) {
            String prefix = dir.replace('\\', '/');
            if (!prefix.endsWith("/")) {
                prefix = prefix + "/";
            }
            if (normalized.startsWith(prefix)) {
                return true;
            }
        }
        return false;
    }
}
