package com.aicheck.analyzer;

import com.aicheck.config.AppConfig;
import com.aicheck.git.GitChangeScanner;
import com.aicheck.model.ChangedClassFile;
import com.aicheck.model.ClassChangeKind;
import com.aicheck.model.ClassChangeReport;
import com.aicheck.model.FieldChange;
import com.aicheck.model.FieldInfo;
import com.aicheck.parser.ClassDeclParser;
import com.aicheck.parser.ClassFieldParser;

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

/**
 * 编排 git 扫描、字段 diff、影响分析，生成待通知的 ClassChangeReport 列表。
 */
public class ClassChangeAnalyzer {
    private final GitChangeScanner gitScanner;
    private final ClassFieldParser classFieldParser = new ClassFieldParser();
    private final FieldDiffEngine fieldDiffEngine = new FieldDiffEngine();
    private final ImpactAnalyzer impactAnalyzer = new ImpactAnalyzer();
    private final ClassDeclParser classDeclParser = new ClassDeclParser();

    public ClassChangeAnalyzer(GitChangeScanner gitScanner) {
        this.gitScanner = gitScanner;
    }

    /** 扫描变更文件并逐条分析，无实质变更的 MODIFIED 会被跳过 */
    public List<ClassChangeReport> analyze(Path repoRoot, AppConfig config, String oldSha, String newSha,
                                           Map<String, com.aicheck.model.ApiEndpoint> endpointIndex) throws IOException {
        List<ChangedClassFile> changedFiles = gitScanner.scanChangedClasses(oldSha, newSha);
        List<ClassChangeReport> reports = new ArrayList<>();

        for (ChangedClassFile changedFile : changedFiles) {
            if (changedFile.getStatus() == ChangedClassFile.ChangeStatus.DELETED) {
                reports.add(analyzeDeleted(changedFile, config, repoRoot, oldSha, endpointIndex));
                continue;
            }
            ClassChangeReport report = analyzeModifiedOrRenamed(changedFile, config, repoRoot, oldSha, newSha, endpointIndex);
            if (report != null) {
                reports.add(report);
            }
        }
        return reports;
    }

    /** 处理删除：标记 DELETED 并分析影响（基于旧源码） */
    private ClassChangeReport analyzeDeleted(ChangedClassFile changedFile, AppConfig config, Path repoRoot,
                                             String oldSha, Map<String, com.aicheck.model.ApiEndpoint> endpointIndex)
            throws IOException {
        String path = changedFile.getRelativePath();
        String oldSource = gitScanner.readFileAtCommit(oldSha, path);

        String classDescription = classDeclParser.extractClassDescription(
                oldSource, changedFile.getClassName());

        ClassChangeReport report = new ClassChangeReport(
                changedFile.getClassName(),
                null,
                changedFile.getClassType(),
                ClassChangeKind.DELETED,
                path,
                config.isDtoEntityConversionEnabled(),
                classDescription
        );
        impactAnalyzer.analyze(report, endpointIndex, config, repoRoot, oldSource, oldSource);
        return report;
    }

    /** 处理修改/重命名：字段 diff → 判定 changeKind → 影响分析 */
    private ClassChangeReport analyzeModifiedOrRenamed(ChangedClassFile changedFile, AppConfig config,
                                                       Path repoRoot, String oldSha, String newSha,
                                                       Map<String, com.aicheck.model.ApiEndpoint> endpointIndex)
            throws IOException {
        String oldPath = changedFile.pathForOldCommit();
        String newPath = changedFile.getRelativePath();

        String oldSource = gitScanner.readFileAtCommit(oldSha, oldPath);
        String newSource = gitScanner.readFileAtCommit(newSha, newPath);
        if (newSource == null || newSource.isBlank()) {
            newSource = gitScanner.readFileAtHead(newPath);
        }

        String oldFallback = ClassDeclParser.classNameFromPath(oldPath);
        String newFallback = ClassDeclParser.classNameFromPath(newPath);
        String oldClassName = changedFile.getOldClassName() != null
                ? changedFile.getOldClassName()
                : classDeclParser.resolveClassName(oldSource, oldFallback);
        String newClassName = classDeclParser.resolveClassName(newSource, newFallback);

        List<FieldInfo> oldFields = classFieldParser.parseFields(oldSource, oldClassName);
        List<FieldInfo> newFields = classFieldParser.parseFields(newSource, newClassName);
        List<FieldChange> fieldChanges = fieldDiffEngine.diff(oldFields, newFields);

        boolean renamed = !oldClassName.equals(newClassName);
        ClassChangeKind changeKind;
        if (renamed && fieldChanges.isEmpty()) {
            changeKind = ClassChangeKind.RENAME_ONLY;
        } else if (renamed) {
            changeKind = ClassChangeKind.RENAME_AND_FIELDS;
        } else if (!fieldChanges.isEmpty()) {
            changeKind = ClassChangeKind.FIELDS_ONLY;
        } else {
            return null;
        }

        String classDescription = classDeclParser.extractClassDescription(newSource, newClassName);

        ClassChangeReport report = new ClassChangeReport(
                newClassName,
                renamed ? oldClassName : null,
                changedFile.getClassType(),
                changeKind,
                newPath,
                config.isDtoEntityConversionEnabled(),
                classDescription
        );
        fieldChanges.forEach(report::addFieldChange);
        impactAnalyzer.analyze(report, endpointIndex, config, repoRoot, newSource, oldSource);
        return report;
    }
}
