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

import com.qqchen.deploy.backend.deploy.converter.JenkinsViewConverter;
import com.qqchen.deploy.backend.deploy.dto.JenkinsSyncHistoryDTO;
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
import com.qqchen.deploy.backend.deploy.entity.JenkinsView;
import com.qqchen.deploy.backend.deploy.dto.JenkinsViewDTO;
import com.qqchen.deploy.backend.deploy.enums.ExternalSystemSyncStatus;
import com.qqchen.deploy.backend.deploy.enums.JenkinsSyncType;
import com.qqchen.deploy.backend.deploy.query.JenkinsViewQuery;
import com.qqchen.deploy.backend.deploy.integration.IJenkinsServiceIntegration;
import com.qqchen.deploy.backend.deploy.integration.response.JenkinsViewResponse;
import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository;
import com.qqchen.deploy.backend.deploy.repository.IJenkinsSyncHistoryRepository;
import com.qqchen.deploy.backend.deploy.repository.IJenkinsViewRepository;
import com.qqchen.deploy.backend.deploy.service.IJenkinsSyncHistoryService;
import com.qqchen.deploy.backend.deploy.service.IJenkinsViewService;
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.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Jenkins视图 Service实现
 */
@Slf4j
@Service
public class JenkinsViewServiceImpl extends BaseServiceImpl<JenkinsView, JenkinsViewDTO, JenkinsViewQuery, Long>
    implements IJenkinsViewService {

    @Resource
    private IExternalSystemRepository externalSystemRepository;

    @Resource
    private IJenkinsViewRepository jenkinsViewRepository;

    @Resource
    private IJenkinsServiceIntegration jenkinsServiceIntegration;

    @Resource
    private com.qqchen.deploy.backend.deploy.repository.IJenkinsJobRepository jenkinsJobRepository;

    @Resource
    private JenkinsViewConverter jenkinsViewConverter;

    @Resource
    private IJenkinsSyncHistoryRepository jenkinsSyncHistoryRepository;

    @Resource
    private IJenkinsSyncHistoryService jenkinsSyncHistoryService;

    @Resource
    private com.qqchen.deploy.backend.deploy.lock.SyncLockManager syncLockManager;

    /**
     * 同步Jenkins视图（异步执行）
     *
     * @param externalSystemId 外部系统ID
     */
    @Override
    @Async
    @Transactional(rollbackFor = Exception.class)
    public void syncViews(Long externalSystemId) {
        // 尝试获取锁
        if (!syncLockManager.tryLock(externalSystemId)) {
            return;
        }

        try {
            doSyncViews(externalSystemId);
        } finally {
            syncLockManager.unlock(externalSystemId);
        }
    }

    private void doSyncViews(Long externalSystemId) {
        // 1. 创建同步历史记录
        JenkinsSyncHistoryDTO syncHistory = new JenkinsSyncHistoryDTO();
        syncHistory.setExternalSystemId(externalSystemId);
        syncHistory.setSyncType(JenkinsSyncType.VIEW);
        syncHistory.setStatus(ExternalSystemSyncStatus.RUNNING);
        jenkinsSyncHistoryService.saveOrUpdateHistory(syncHistory);

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

            // 3. 调用Jenkins API获取视图列表
            List<JenkinsViewResponse> viewResponses = jenkinsServiceIntegration.listViews(externalSystem);
            if (viewResponses.isEmpty()) {
                log.debug("No views found in Jenkins system: {}", externalSystemId);
                // 更新同步历史为成功
                syncHistory.setStatus(ExternalSystemSyncStatus.SUCCESS);
                jenkinsSyncHistoryService.saveOrUpdateHistory(syncHistory);
                return;
            }

            // 4. 转换并保存/更新视图数据
            List<JenkinsView> jenkinsViews = new ArrayList<>();
            for (JenkinsViewResponse viewResponse : viewResponses) {
                // 查找是否存在相同的视图
                Optional<JenkinsView> existingView = jenkinsViewRepository
                    .findByExternalSystemIdAndViewName(externalSystemId, viewResponse.getName());

                JenkinsView jenkinsView;
                if (existingView.isPresent()) {
                    // 更新已存在的视图
                    jenkinsView = existingView.get();
                    updateViewFromResponse(jenkinsView, viewResponse);
                    log.debug("Updating existing Jenkins view: {}", jenkinsView.getViewName());
                } else {
                    // 创建新的视图
                    jenkinsView = new JenkinsView();
                    jenkinsView.setExternalSystemId(externalSystemId);
                    jenkinsView.setViewName(viewResponse.getName());
                    updateViewFromResponse(jenkinsView, viewResponse);
                    log.debug("Creating new Jenkins view: {}", jenkinsView.getViewName());
                }
                jenkinsViews.add(jenkinsView);
            }

            // 5. 批量保存或更新
            jenkinsViewRepository.saveAll(jenkinsViews);
            log.info("Successfully synchronized {} Jenkins views for external system: {}", jenkinsViews.size(), externalSystemId);

            // 6. 更新同步历史为成功
            syncHistory.setStatus(ExternalSystemSyncStatus.SUCCESS);
            jenkinsSyncHistoryService.saveOrUpdateHistory(syncHistory);
        } catch (Exception e) {
            log.error("Failed to sync Jenkins views for external system: {}", externalSystemId, e);
            syncHistory.setStatus(ExternalSystemSyncStatus.FAILED);
            syncHistory.setErrorMessage(e.getMessage());
            jenkinsSyncHistoryService.saveOrUpdateHistory(syncHistory);
            throw e;
        }
    }

    /**
     * 从API响应更新视图信息
     */
    private void updateViewFromResponse(JenkinsView jenkinsView, JenkinsViewResponse response) {
        jenkinsView.setDescription(response.getDescription());
        jenkinsView.setViewUrl(response.getUrl());
    }

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

    /**
     * 重写分页方法，增加关联任务数统计
     */
    @Override
    public org.springframework.data.domain.Page<JenkinsViewDTO> page(JenkinsViewQuery query) {
        org.springframework.data.domain.Page<JenkinsViewDTO> page = super.page(query);
        fillJobCounts(page.getContent());
        return page;
    }

    /**
     * 重写列表方法，增加关联任务数统计
     */
    @Override
    public List<JenkinsViewDTO> findAll(JenkinsViewQuery query) {
        List<JenkinsViewDTO> list = super.findAll(query);
        fillJobCounts(list);
        return list;
    }
    
    /**
     * 批量填充视图的任务数量（解决N+1查询问题）
     */
    private void fillJobCounts(List<JenkinsViewDTO> views) {
        if (views.isEmpty()) {
            return;
        }
        
        // 1. 收集所有视图ID
        Set<Long> viewIds = views.stream()
            .map(JenkinsViewDTO::getId)
            .collect(Collectors.toSet());
        
        // 2. 批量查询任务数量（1条SQL）
        List<Object[]> countResults = jenkinsJobRepository.countByViewIds(viewIds);
        Map<Long, Long> jobCountMap = countResults.stream()
            .collect(Collectors.toMap(
                arr -> (Long) arr[0],  // viewId
                arr -> (Long) arr[1]   // count
            ));
        
        // 3. 填充数据
        views.forEach(view -> {
            Long jobCount = jobCountMap.getOrDefault(view.getId(), 0L);
            view.setJobCount(jobCount);
        });
    }
}