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

import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
import com.qqchen.deploy.backend.deploy.entity.JenkinsJob;
import com.qqchen.deploy.backend.deploy.enums.JenkinsBuildStatus;
import com.qqchen.deploy.backend.deploy.integration.IJenkinsServiceIntegration;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsQueueBuildInfoResponse;
import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository;
import com.qqchen.deploy.backend.deploy.repository.IJenkinsJobRepository;
import com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants;
import com.qqchen.deploy.backend.workflow.dto.inputmapping.JenkinsBuildInputMapping;
import com.qqchen.deploy.backend.workflow.dto.outputs.JenkinsBuildOutputs;
import com.qqchen.deploy.backend.workflow.enums.NodeExecutionStatusEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.BpmnError;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * Jenkins构建任务委派
 * 
 * @author qqchen
 * @since 2025-10-22
 */
@Slf4j
@Component("jenkinsBuildDelegate")
public class JenkinsBuildDelegate extends BaseNodeDelegate<JenkinsBuildInputMapping, JenkinsBuildOutputs> {

    @Resource
    private IJenkinsServiceIntegration jenkinsServiceIntegration;

    @Resource
    private IExternalSystemRepository externalSystemRepository;

    @Resource
    private IJenkinsJobRepository jenkinsJobRepository;

    private static final int QUEUE_POLL_INTERVAL = 10; // 10秒
    private static final int MAX_QUEUE_POLLS = 30; // 最多等待5分钟
    private static final int BUILD_POLL_INTERVAL = 10; // 轮询间隔（秒）
    private static final int MAX_BUILD_POLLS = 180; // 30分钟超时

    @Override
    protected JenkinsBuildOutputs executeInternal(
            DelegateExecution execution,
            Map<String, Object> configs,
            JenkinsBuildInputMapping input
    ) {
        log.info("Jenkins Build - serverId: {}, jobName: {}", 
            input.getJenkinsServerId(), input.getProject());

        // 1. 获取外部系统
        ExternalSystem externalSystem = externalSystemRepository.findById(input.getJenkinsServerId().longValue())
            .orElseThrow(() -> new RuntimeException("Jenkins服务器不存在: " + input.getJenkinsServerId()));
        
        String jobName = input.getProject();
        
        // 2. 触发构建
        Map<String, String> parameters = new HashMap<>();
        // 可以根据需要添加构建参数
        // parameters.put("BRANCH", "main");
        
        String queueId = jenkinsServiceIntegration.buildWithParameters(
            externalSystem, jobName, parameters);
        
        // 3. 等待构建从队列中开始
        JenkinsQueueBuildInfoResponse buildInfo = waitForBuildToStart(queueId);
        
        // 4. 轮询构建状态直到完成
        // 注意：如果构建失败或被取消，pollBuildStatus 会抛出 BpmnError，触发错误边界事件
        // 只有成功时才会返回到这里
        JenkinsBuildStatus buildStatus = pollBuildStatus(externalSystem, jobName, buildInfo.getBuildNumber());

        // 5. 获取构建详细信息（包括 duration, changeSets, artifacts）
        com.qqchen.deploy.backend.deploy.integration.response.JenkinsBuildResponse buildDetails = 
            jenkinsServiceIntegration.getBuildDetails(externalSystem, jobName, buildInfo.getBuildNumber());

        // 打印调试信息
        log.info("Build details - changeSets: {}, artifacts: {}", 
            buildDetails.getChangeSets(), buildDetails.getArtifacts());

        // 6. 构造输出结果（执行到这里说明构建成功）
        JenkinsBuildOutputs outputs = new JenkinsBuildOutputs();
        
        // 设置统一的执行状态为成功
        outputs.setStatus(NodeExecutionStatusEnum.SUCCESS);
        
        // 设置 Jenkins 特有字段
        outputs.setBuildStatus(buildStatus.name());
        outputs.setBuildNumber(buildInfo.getBuildNumber());
        outputs.setBuildUrl(buildInfo.getBuildUrl());
        
        // 从构建详情中提取信息
        outputs.setBuildDuration(buildDetails.getDuration() != null ? buildDetails.getDuration().intValue() : 0);
        
        // 提取 Git Commit ID（从 changeSets 中获取第一个）
        if (buildDetails.getChangeSets() != null && !buildDetails.getChangeSets().isEmpty()) {
            log.info("Found {} changeSets", buildDetails.getChangeSets().size());
            var changeSet = buildDetails.getChangeSets().get(0);
            if (changeSet.getItems() != null && !changeSet.getItems().isEmpty()) {
                log.info("Found {} items in changeSet", changeSet.getItems().size());
                outputs.setGitCommitId(changeSet.getItems().get(0).getCommitId());
            }
        } else {
            log.warn("No changeSets found in build details");
        }
        if (outputs.getGitCommitId() == null) {
            outputs.setGitCommitId("");
        }
        
        // 提取构建制品URL（如果有多个制品，拼接成逗号分隔的列表）
        if (buildDetails.getArtifacts() != null && !buildDetails.getArtifacts().isEmpty()) {
            log.info("Found {} artifacts", buildDetails.getArtifacts().size());
            String artifactUrls = buildDetails.getArtifacts().stream()
                .map(artifact -> buildInfo.getBuildUrl() + "artifact/" + artifact.getRelativePath())
                .collect(java.util.stream.Collectors.joining(","));
            outputs.setArtifactUrl(artifactUrls);
        } else {
            log.warn("No artifacts found in build details");
            outputs.setArtifactUrl("");
        }
        
        return outputs;
    }

    private JenkinsQueueBuildInfoResponse waitForBuildToStart(String queueId) {
        int attempts = 0;
        while (attempts < MAX_QUEUE_POLLS) {
            try {
                JenkinsQueueBuildInfoResponse buildInfo = jenkinsServiceIntegration.getQueuedBuildInfo(queueId);
                if (buildInfo != null) {
                    return buildInfo;
                }

                log.debug("Build still in queue, waiting... attempts: {}/{}", attempts + 1, MAX_QUEUE_POLLS);

                Thread.sleep(QUEUE_POLL_INTERVAL * 1000L);
                attempts++;

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new BpmnError("POLLING_INTERRUPTED", "Interrupted while waiting for build to start");
            }
        }

        throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, String.format("Build did not start within %d seconds", MAX_QUEUE_POLLS * QUEUE_POLL_INTERVAL));
    }

    private JenkinsBuildStatus pollBuildStatus(ExternalSystem externalSystem, String jobName, Integer buildNumber) {
        int attempts = 0;
        while (attempts < MAX_BUILD_POLLS) {
            try {
                // 等待一定时间后再检查
                Thread.sleep(BUILD_POLL_INTERVAL * 1000L);

                // 获取构建状态
                JenkinsBuildStatus status = jenkinsServiceIntegration.getBuildStatus(externalSystem, jobName, buildNumber);
                log.info("Jenkins build status: job={}, buildNumber={}, status={}", jobName, buildNumber, status);

                switch (status) {
                    case SUCCESS:
                        // 构建成功，返回状态
                        log.info("Jenkins build succeeded: job={}, buildNumber={}", jobName, buildNumber);
                        return status;
                    case FAILURE:
                        // 构建失败，抛出错误（触发边界事件）
                        throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, 
                            String.format("Jenkins build failed: job=%s, buildNumber=%d", jobName, buildNumber));
                    case ABORTED:
                        // 构建被取消，抛出错误（触发边界事件）
                        throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, 
                            String.format("Jenkins build was aborted: job=%s, buildNumber=%d", jobName, buildNumber));
                    case IN_PROGRESS:
                        // 继续轮询
                        attempts++;
                        break;
                    case NOT_FOUND:
                        // 构建记录丢失，抛出系统异常
                        throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, 
                            String.format("Jenkins build not found: job=%s, buildNumber=%d", jobName, buildNumber));
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, "Build status polling was interrupted");
            }
        }
        // 超过最大轮询次数，视为超时（系统异常）
        throw new BpmnError(WorkFlowConstants.WORKFLOW_EXEC_ERROR, 
            String.format("Jenkins build timed out after %d minutes: job=%s, buildNumber=%d", 
                MAX_BUILD_POLLS * BUILD_POLL_INTERVAL / 60, jobName, buildNumber));
    }
}
