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.IExternalSystemIntegration;
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.definition.node.localVariables.DeployNodeLocalVariables;
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.DeployNodePanelVariables;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.BpmnError;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Shell脚本任务的委派者实现
 */
@Slf4j
@Component
public class DeployNodeDelegate extends BaseNodeDelegate<DeployNodePanelVariables, DeployNodeLocalVariables> {

    @Resource
    private IJenkinsServiceIntegration jenkinsServiceIntegration;

    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分钟超时

    @Resource
    private IExternalSystemRepository externalSystemRepository;

    @Resource
    private IJenkinsJobRepository jenkinsJobRepository;

    @Override
    protected Class<DeployNodePanelVariables> getPanelVariablesClass() {
        return DeployNodePanelVariables.class;
    }

    @Override
    protected Class<DeployNodeLocalVariables> getLocalVariablesClass() {
        return DeployNodeLocalVariables.class;
    }

    @Override
    protected void executeInternal(DelegateExecution execution, DeployNodePanelVariables panelVariables, DeployNodeLocalVariables localVariables) {
        ExternalSystem externalSystem = externalSystemRepository.findById(localVariables.getExternalSystemId()).orElseThrow(() -> new RuntimeException("ExternalSystem not found!!!"));
        JenkinsJob jenkinsJob = jenkinsJobRepository.findById(localVariables.getJobId()).orElseThrow(() -> new RuntimeException("Jenkins job not found!!!"));
        Map<String, String> parameters = new HashMap<>();
        parameters.put("PIPELINE_SCRIPT", localVariables.getScript());
        String queueId = jenkinsServiceIntegration.buildWithParameters(externalSystem, jenkinsJob.getJobName(), parameters);
        JenkinsQueueBuildInfoResponse buildInfo = waitForBuildToStart(queueId);
        // 3. 轮询构建状态
        pollBuildStatus(externalSystem, jenkinsJob.getJobName(), buildInfo.getBuildNumber());
    }

    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 void 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:
                        // 构建成功，返回继续流程
                        return;
                    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));
    }
}
