package com.qqchen.deploy.backend.deploy.service.impl;

import com.qqchen.deploy.backend.deploy.converter.JenkinsJobConverter;
import com.qqchen.deploy.backend.deploy.dto.JenkinsSyncHistoryDTO;
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
import com.qqchen.deploy.backend.deploy.entity.JenkinsJob;
import com.qqchen.deploy.backend.deploy.entity.JenkinsView;
import com.qqchen.deploy.backend.deploy.dto.JenkinsJobDTO;
import com.qqchen.deploy.backend.deploy.enums.ExternalSystemSyncStatus;
import com.qqchen.deploy.backend.deploy.enums.JenkinsSyncType;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsHealthReportResponse;
import com.qqchen.deploy.backend.deploy.query.JenkinsJobQuery;
import com.qqchen.deploy.backend.deploy.integration.IJenkinsServiceIntegration;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsJobResponse;
import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository;
import com.qqchen.deploy.backend.deploy.repository.IJenkinsJobRepository;
import com.qqchen.deploy.backend.deploy.repository.IJenkinsViewRepository;
import com.qqchen.deploy.backend.deploy.service.IJenkinsJobService;
import com.qqchen.deploy.backend.deploy.service.IJenkinsSyncHistoryService;
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalDouble;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Jenkins任务 Service实现
 */
@Slf4j
@Service
public class JenkinsJobServiceImpl extends BaseServiceImpl<JenkinsJob, JenkinsJobDTO, JenkinsJobQuery, Long>
    implements IJenkinsJobService {

    @Resource
    private IExternalSystemRepository externalSystemRepository;

    @Resource
    private IJenkinsViewRepository jenkinsViewRepository;

    @Resource
    private IJenkinsJobRepository jenkinsJobRepository;

    @Resource
    private IJenkinsServiceIntegration jenkinsServiceIntegration;

    @Resource
    private JenkinsJobConverter jenkinsJobConverter;

    @Resource
    private IJenkinsSyncHistoryService jenkinsSyncHistoryService;

    /**
     * 同步外部系统下所有视图的Jenkins任务
     *
     * @param externalSystemId 外部系统ID
     * @return 同步的任务总数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer syncJobs(Long externalSystemId) {
        // 1. 创建同步历史记录
        JenkinsSyncHistoryDTO syncHistory = new JenkinsSyncHistoryDTO();
        syncHistory.setExternalSystemId(externalSystemId);
        syncHistory.setSyncType(JenkinsSyncType.JOB);
        syncHistory.setStatus(ExternalSystemSyncStatus.RUNNING);
        jenkinsSyncHistoryService.saveOrUpdateHistory(syncHistory);

        try {
            // 2. 查询外部系统
            ExternalSystem externalSystem = externalSystemRepository.findById(externalSystemId).orElseThrow(() -> new BusinessException(ResponseCode.EXTERNAL_SYSTEM_NOT_FOUND));

            // 3. 查询该外部系统下的所有视图
            List<JenkinsView> views = jenkinsViewRepository.findByExternalSystemId(externalSystemId);
            if (views.isEmpty()) {
                log.info("No views found for external system: {}", externalSystemId);
                // 更新同步历史为成功
                syncHistory.setStatus(ExternalSystemSyncStatus.SUCCESS);
                jenkinsSyncHistoryService.saveOrUpdateHistory(syncHistory);
                return 0;
            }

            // 4. 遍历所有视图，同步每个视图下的任务
            int totalSyncedJobs = 0;
            StringBuilder errorMessages = new StringBuilder();
            for (JenkinsView view : views) {
                try {
                    Integer syncedJobs = syncJobsByView(externalSystem, view);
                    totalSyncedJobs += syncedJobs;
                    log.info("Successfully synchronized {} jobs for view: {}", syncedJobs, view.getViewName());
                } catch (Exception e) {
                    // 记录错误但继续同步其他视图
                    String errorMessage = String.format("Failed to sync jobs for view %s: %s", view.getViewName(), e.getMessage());
                    log.error(errorMessage, e);
                    errorMessages.append(errorMessage).append("\n");
                }
            }

            // 5. 更新同步历史状态
            if (errorMessages.length() > 0) {
                syncHistory.setStatus(ExternalSystemSyncStatus.FAILED);
                syncHistory.setErrorMessage(errorMessages.toString());
            } else {
                syncHistory.setStatus(ExternalSystemSyncStatus.SUCCESS);
            }
            jenkinsSyncHistoryService.saveOrUpdateHistory(syncHistory);

            log.info("Successfully synchronized total {} jobs for external system: {}", totalSyncedJobs, externalSystemId);
            return totalSyncedJobs;
        } catch (Exception e) {
            log.error("Failed to sync Jenkins jobs for external system: {}", externalSystemId, e);
            // 更新同步历史为失败
            syncHistory.setStatus(ExternalSystemSyncStatus.FAILED);
            syncHistory.setErrorMessage(e.getMessage());
            jenkinsSyncHistoryService.saveOrUpdateHistory(syncHistory);
            throw e;
        }
    }

    /**
     * 同步指定视图下的Jenkins任务
     *
     * @param externalSystem 外部系统
     * @param view 视图
     * @return 同步的任务数量
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer syncJobsByView(ExternalSystem externalSystem, JenkinsView view) {
        // 1. 获取Jenkins任务列表
        List<JenkinsJobResponse> jobResponses = jenkinsServiceIntegration.listJobs(externalSystem, view.getViewName());
        if (jobResponses.isEmpty()) {
            log.info("No jobs found in Jenkins view: {}", view.getViewName());
            return 0;
        }

        // 2. 查询现有任务
        List<JenkinsJob> existingJobs = jenkinsJobRepository.findByExternalSystemIdAndViewId(
            externalSystem.getId(),
            view.getId()
        );
        Map<String, JenkinsJob> jobMap = existingJobs.stream()
            .collect(Collectors.toMap(JenkinsJob::getJobName, Function.identity()));

        // 3. 转换并保存/更新任务数据
        List<JenkinsJob> jenkinsJobs = new ArrayList<>();
        for (JenkinsJobResponse jobResponse : jobResponses) {
            JenkinsJob jenkinsJob = jobMap.getOrDefault(jobResponse.getName(), new JenkinsJob());
            
            // 设置基本信息
            jenkinsJob.setExternalSystemId(externalSystem.getId());
            jenkinsJob.setViewId(view.getId());
            jenkinsJob.setJobName(jobResponse.getName());
            
            // 更新任务信息
            updateJobFromResponse(jenkinsJob, jobResponse);
            
            // 添加到待保存列表
            jenkinsJobs.add(jenkinsJob);
            log.debug("{} Jenkins job: {}", jenkinsJob.getId() == null ? "Creating new" : "Updating existing", jenkinsJob.getJobName());
        }

        // 4. 批量保存或更新
        jenkinsJobRepository.saveAll(jenkinsJobs);
        
        log.info("Successfully synchronized {} Jenkins jobs for view: {}", jenkinsJobs.size(), view.getViewName());
        return jenkinsJobs.size();
    }

    /**
     * 从API响应更新任务信息
     */
    private void updateJobFromResponse(JenkinsJob jenkinsJob, JenkinsJobResponse response) {
        jenkinsJob.setBuildable(response.getBuildable());
        jenkinsJob.setDescription(response.getDescription());
        jenkinsJob.setJobUrl(response.getUrl());
        jenkinsJob.setNextBuildNumber(response.getNextBuildNumber());
        
        // 设置最后构建信息
        if (response.getLastBuild() != null) {
            jenkinsJob.setLastBuildNumber(response.getLastBuild().getNumber());
            jenkinsJob.setLastBuildStatus(convertColorToStatus(response.getColor()));
            
            // 设置最后构建时间
            if (response.getLastBuild().getTimestamp() != null) {
                jenkinsJob.setLastBuildTime(LocalDateTime.ofInstant(
                    Instant.ofEpochMilli(response.getLastBuild().getTimestamp()),
                    ZoneId.systemDefault()
                ));
            }
        } else {
            // 如果没有最后构建信息，设置默认值
            jenkinsJob.setLastBuildNumber(0);
            jenkinsJob.setLastBuildStatus("NOT_BUILT");
            jenkinsJob.setLastBuildTime(null);
        }
        
        // 设置健康分数
        jenkinsJob.setHealthReportScore(calculateHealthScore(response));
    }

    /**
     * 将Jenkins颜色转换为构建状态
     */
    private String convertColorToStatus(String color) {
        if (color == null) return "UNKNOWN";
        return switch (color) {
            case "blue" -> "SUCCESS";
            case "red" -> "FAILURE";
            case "yellow" -> "UNSTABLE";
            case "grey", "disabled" -> "DISABLED";
            case "notbuilt" -> "NOT_BUILT";
            case "aborted" -> "ABORTED";
            default -> "UNKNOWN";
        };
    }

    /**
     * 计算任务健康分数
     * Jenkins健康分数基于以下几个方面：
     * 1. 构建稳定性（最近构建的成功率）
     * 2. 测试结果
     * 3. 代码覆盖率
     * 4. 静态代码分析结果等
     * 
     * @param response Jenkins任务响应
     * @return 健康分数（0-100）
     */
    private Integer calculateHealthScore(JenkinsJobResponse response) {
        // 如果任务被禁用，返回0分
        if (!response.getBuildable()) {
            return 0;
        }

        // 获取任务的健康报告
        List<JenkinsHealthReportResponse> healthReports = response.getHealthReports();
        if (healthReports == null || healthReports.isEmpty()) {
            // 如果没有健康报告，根据最近构建状态判断
            return calculateScoreByBuildStatus(response);
        }

        // 如果有多个健康报告，取平均分
        OptionalDouble avgScore = healthReports.stream()
            .mapToInt(JenkinsHealthReportResponse::getScore)
            .average();
            
        return avgScore.isPresent() ? (int) avgScore.getAsDouble() : 0;
    }

    /**
     * 根据构建状态计算分数
     */
    private Integer calculateScoreByBuildStatus(JenkinsJobResponse response) {
        String color = response.getColor();
        if (color == null) {
            return 0;
        }

        return switch (color) {
            case "blue" -> 100;        // 成功
            case "yellow" -> 70;       // 不稳定
            case "red" -> 40;          // 失败
            case "grey" -> 0;          // 禁用
            case "disabled" -> 0;      // 禁用
            case "notbuilt" -> 50;     // 未构建
            case "aborted" -> 60;      // 中断
            default -> 0;
        };
    }

    @Override
    public List<JenkinsJobDTO> findByExternalSystemId(Long externalSystemId) {
        JenkinsJobQuery query = new JenkinsJobQuery();
        query.setExternalSystemId(externalSystemId);
        return super.findAll(query);
    }
} 