package com.qqchen.deploy.backend.workflow.delegate;

import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
import com.qqchen.deploy.backend.deploy.integration.IGitServiceIntegration;
import com.qqchen.deploy.backend.deploy.integration.response.GitCommitResponse;
import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository;
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.framework.utils.DateUtils;
import com.qqchen.deploy.backend.workflow.dto.CommitDifferenceInfo;
import com.qqchen.deploy.backend.workflow.dto.inputmapping.GitSyncCheckInputMapping;
import com.qqchen.deploy.backend.workflow.dto.outputs.GitSyncCheckOutputs;
import com.qqchen.deploy.backend.workflow.enums.NodeExecutionStatusEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Git同步检测节点委派
 *
 * @author qqchen
 * @since 2025-12-04
 */
@Slf4j
@Component("gitSyncCheckDelegate")
public class GitSyncCheckDelegate extends BaseNodeDelegate<GitSyncCheckInputMapping, GitSyncCheckOutputs> {

    @Resource
    private IGitServiceIntegration gitServiceIntegration;
    
    @Resource
    private IExternalSystemRepository externalSystemRepository;
    
    /**
     * 获取commits的数量限制（用于检测）
     */
    private static final int COMMITS_LIMIT = 50;
    
    /**
     * 通知中显示的commit数量限制（防止内容过长）
     */
    private static final int DISPLAY_COMMITS_LIMIT = 5;
    
    @Override
    protected void executeInternal(DelegateExecution execution, Map<String, Object> configs, GitSyncCheckInputMapping input) {
        
        log.info("开始Git同步检测 - 源分支: {}/{}/{}, 目标分支: {}/{}/{}", input.getSourceGitSystemId(), input.getSourceGitProjectId(), input.getSourceBranch(), input.getTargetGitSystemId(), input.getTargetGitProjectId(), input.getTargetBranch());
        
        try {
            // 0. 检查是否配置了目标Git信息（非强制，如果未配置则跳过检测）
            if (input.getTargetGitSystemId() == null || 
                input.getTargetGitProjectId() == null || 
                input.getTargetBranch() == null || 
                input.getTargetBranch().trim().isEmpty()) {
                
                String skipReason = "目标Git系统未配置，跳过Git同步检测（团队可能未启用同步模式）";
                log.info("{}", skipReason);
                output.setStatus(NodeExecutionStatusEnum.SUCCESS);
                output.setMessage(skipReason);
                output.setCheckDetail(skipReason);
                output.setHasDifference(false);
                output.setCommitsAhead(0);
                output.setCommitsBehind(0);
                logInfo(skipReason);
                return; // 直接返回成功，不影响流程
            }
            
            // 1. 查询Git系统配置（技术异常 - 强制失败）
            ExternalSystem sourceSystem = externalSystemRepository.findById(input.getSourceGitSystemId())
                    .orElseThrow(() -> new BusinessException(ResponseCode.EXTERNAL_SYSTEM_NOT_FOUND, 
                            new Object[]{"源Git系统不存在: " + input.getSourceGitSystemId()}));
            
            ExternalSystem targetSystem = externalSystemRepository.findById(input.getTargetGitSystemId())
                    .orElseThrow(() -> new BusinessException(ResponseCode.EXTERNAL_SYSTEM_NOT_FOUND,
                            new Object[]{"目标Git系统不存在: " + input.getTargetGitSystemId()}));
            
            // 2. 获取源分支最近10个commits
            List<GitCommitResponse> sourceCommits = gitServiceIntegration.getCommits(
                    sourceSystem, 
                    input.getSourceGitProjectId(), 
                    input.getSourceBranch(), 
                    COMMITS_LIMIT
            );
            
            // 业务失败：源分支不存在或无法获取提交记录
            if (sourceCommits.isEmpty()) {
                String errorMsg = String.format("无法获取源分支提交记录: %s (分支可能不存在)", input.getSourceBranch());
                log.warn(errorMsg);
                output.setStatus(NodeExecutionStatusEnum.FAILURE);
                output.setMessage(errorMsg);
                output.setCheckDetail(errorMsg);
                logWarn(errorMsg);
                return; // 正常返回，由基类根据 continueOnFailure 决定是否抛 BpmnError
            }
            
            // 3. 获取目标分支最近10个commits
            List<GitCommitResponse> targetCommits = gitServiceIntegration.getCommits(
                    targetSystem, 
                    input.getTargetGitProjectId(), 
                    input.getTargetBranch(), 
                    COMMITS_LIMIT
            );
            
            // 业务失败：目标分支不存在或无法获取提交记录
            if (targetCommits.isEmpty()) {
                String errorMsg = String.format("无法获取目标分支提交记录: %s (分支可能不存在)", input.getTargetBranch());
                log.warn(errorMsg);
                output.setStatus(NodeExecutionStatusEnum.FAILURE);
                output.setMessage(errorMsg);
                output.setCheckDetail(errorMsg);
                logWarn(errorMsg);
                return; // 正常返回，由基类根据 continueOnFailure 决定是否抛 BpmnError
            }
            
            // 4. 比较commits，找出差异
            CompareResult compareResult = compareCommits(sourceCommits, targetCommits);
            
            // 5. 填充输出结果
            output.setSourceLatestCommit(sourceCommits.get(0).getId());
            output.setTargetLatestCommit(targetCommits.get(0).getId());
            output.setHasDifference(compareResult.hasDifference);
            output.setCommitsAhead(compareResult.commitsAhead);
            output.setCommitsBehind(compareResult.commitsBehind);
            output.setDifferenceCommits(compareResult.differenceCommits);
            
            // 6. 判断检测结果
            if (!compareResult.hasDifference) {
                // 合规：目标分支的所有commits都在源分支中
                String detail = String.format(
                    "[%s] %s 与 [%s] %s 代码已同步",
                    sourceSystem.getName(),
                    input.getSourceBranch(),
                    targetSystem.getName(),
                    input.getTargetBranch()
                );
                output.setStatus(NodeExecutionStatusEnum.SUCCESS);
                output.setMessage(detail);
                output.setCheckDetail(detail);
                logInfo(detail);
                
            } else {
                // 不合规：目标分支有源分支没有的commits
                StringBuilder detailBuilder = new StringBuilder();
                
                // 添加Git系统和分支信息
                detailBuilder.append(String.format(
                    "[%s] %s 存在 %d 个未回归到 [%s] %s 的提交\n\n",
                    targetSystem.getName(),
                    input.getTargetBranch(),
                    compareResult.commitsBehind,
                    sourceSystem.getName(),
                    input.getSourceBranch()
                ));
                
                // 只显示前N个commits，避免内容过长
                int displayCount = Math.min(DISPLAY_COMMITS_LIMIT, compareResult.differenceCommits.size());
                detailBuilder.append(String.format("最近%d个提交：\n", displayCount));
                
                for (int i = 0; i < displayCount; i++) {
                    CommitDifferenceInfo commit = compareResult.differenceCommits.get(i);
                    detailBuilder.append(String.format(
                        "%d. [%s] %s (%s %s)\n",
                        i + 1,
                        commit.getCommitId().substring(0, 8),
                        commit.getShortMessage(),
                        commit.getAuthor(),
                        DateUtils.format(commit.getCommittedDate())
                    ));
                }
                
                // 如果还有更多未显示的提交
                if (compareResult.commitsBehind > displayCount) {
                    detailBuilder.append(String.format(
                        "\n...还有 %d 个未显示的提交\n",
                        compareResult.commitsBehind - displayCount
                    ));
                }
                
                // 简化操作指引
                detailBuilder.append(String.format(
                    "\n请将上述提交回归到 [%s] %s 或确认为客户定制化代码",
                    sourceSystem.getName(),
                    input.getSourceBranch()
                ));
                
                String detail = detailBuilder.toString();
                output.setStatus(NodeExecutionStatusEnum.FAILURE);
                output.setCheckDetail(detail);
                output.setMessage(String.format(
                    "目标分支存在%d个未回归的提交，请检查",
                    compareResult.commitsBehind
                ));
                logWarn(detail);
                
                // 正常返回，基类会根据 output.status + continueOnFailure 决定是否抛 BpmnError
            }
            
        } catch (BusinessException e) {
            // 技术异常（Git系统不存在等）- 直接抛出，强制失败
            log.error("Git同步检测技术异常", e);
            throw e;
            
        } catch (Exception e) {
            // 未预期的异常 - 标记为失败，友好处理
            log.error("Git同步检测发生异常", e);
            output.setStatus(NodeExecutionStatusEnum.FAILURE);
            output.setMessage("Git同步检测异常: " + e.getMessage());
            output.setCheckDetail("系统异常: " + e.getMessage());
            logError("Git同步检测异常: " + e.getMessage());
            
            // ✅ 正常返回，基类会根据 output.status + continueOnFailure 决定是否抛 BpmnError
        }
    }
    
    /**
     * 比较两个分支的commits（基于源分支为基准的规则）
     * 
     * <p><b>核心规则</b>：源分支（公司Git）是基准，所有代码都应该回归到源分支
     * <ul>
     *   <li>如果目标分支中有任何commit不在源分支中 → <b>不合规</b></li>
     *   <li>需要将目标分支独有的commits列出来，放到checkDetail中供通知使用</li>
     * </ul>
     * 
     * @param sourceCommits 源分支的最近N个commits（公司Git，基准）
     * @param targetCommits 目标分支的最近N个commits（客户Git）
     * @return 比较结果
     */
    private CompareResult compareCommits(List<GitCommitResponse> sourceCommits, List<GitCommitResponse> targetCommits) {
        CompareResult result = new CompareResult();
        
        // 构建源分支commit ID集合（基准）
        Set<String> sourceCommitIds = sourceCommits.stream()
                .map(GitCommitResponse::getId)
                .collect(Collectors.toSet());
        
        // 找出目标分支中有但源分支中没有的commits（不合规的commits）
        List<GitCommitResponse> nonCompliantCommits = targetCommits.stream()
                .filter(commit -> !sourceCommitIds.contains(commit.getId()))
                .collect(Collectors.toList());
        
        if (nonCompliantCommits.isEmpty()) {
            // 目标分支的所有commits都在源分支中 → 合规
            result.hasDifference = false;
            result.commitsAhead = 0;
            result.commitsBehind = 0;
            result.differenceCommits = Collections.emptyList();
            
            log.info("Git同步检测通过 - 目标分支的所有提交都已回归到源分支");
            return result;
        }
        
        // 存在不合规的commits
        result.hasDifference = true;
        result.commitsAhead = 0; // 不关心源分支领先多少
        result.commitsBehind = nonCompliantCommits.size(); // 目标分支独有的commit数量
        result.differenceCommits = buildDifferenceList(nonCompliantCommits, "target");
        
        log.warn("Git同步检测不合规 - 目标分支存在{}个未回归到源分支的提交", 
                nonCompliantCommits.size());
        
        // 打印不合规的commits（用于调试）
        nonCompliantCommits.forEach(commit -> 
            log.warn("  - 不合规commit: {} by {} at {}", 
                    commit.getId().substring(0, 8),
                    commit.getAuthorName(),
                    commit.getCommittedDateTime())
        );
        
        return result;
    }
    
    /**
     * 构建差异提交信息列表
     */
    private List<CommitDifferenceInfo> buildDifferenceList(List<GitCommitResponse> commits, String branchLabel) {
        return commits.stream()
                .map(commit -> {
                    CommitDifferenceInfo info = new CommitDifferenceInfo();
                    info.setCommitId(commit.getId());
                    info.setAuthor(commit.getAuthorName());
                    info.setAuthorEmail(commit.getAuthorEmail());
                    info.setCommittedDate(commit.getCommittedDateTime());
                    info.setMessage(commit.getMessage());
                    info.setShortMessage(truncateMessage(commit.getTitle(), 100));
                    info.setBranch(branchLabel);
                    return info;
                })
                .collect(Collectors.toList());
    }
    
    /**
     * 截断消息
     */
    private String truncateMessage(String message, int maxLength) {
        if (message == null) {
            return "N/A";
        }
        if (message.length() <= maxLength) {
            return message;
        }
        return message.substring(0, maxLength - 3) + "...";
    }
    
    /**
     * 比较结果内部类
     */
    private static class CompareResult {
        /**
         * 是否存在差异（目标分支是否有未回归的commits）
         */
        boolean hasDifference;
        
        /**
         * 源分支领先数量（本规则下不使用，始终为0）
         */
        int commitsAhead;
        
        /**
         * 目标分支独有的commit数量（未回归到源分支的commits）
         */
        int commitsBehind;
        
        /**
         * 不合规的commits列表（目标分支独有的）
         */
        List<CommitDifferenceInfo> differenceCommits;
    }
}
