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

import com.qqchen.deploy.backend.deploy.converter.RepositoryGroupConverter;
import com.qqchen.deploy.backend.deploy.dto.RepositorySyncHistoryDTO;
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
import com.qqchen.deploy.backend.deploy.entity.RepositoryGroup;
import com.qqchen.deploy.backend.deploy.dto.RepositoryGroupDTO;
import com.qqchen.deploy.backend.deploy.enums.ExternalSystemSyncStatus;
import com.qqchen.deploy.backend.deploy.enums.RepositorySyncType;
import com.qqchen.deploy.backend.deploy.integration.IGitServiceIntegration;
import com.qqchen.deploy.backend.deploy.integration.response.GitGroupResponse;
import com.qqchen.deploy.backend.deploy.query.RepositoryGroupQuery;
import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository;
import com.qqchen.deploy.backend.deploy.repository.IRepositoryGroupRepository;
import com.qqchen.deploy.backend.deploy.repository.IRepositoryProjectRepository;
import com.qqchen.deploy.backend.deploy.service.IRepositoryGroupService;
import com.qqchen.deploy.backend.deploy.service.IRepositorySyncHistoryService;
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.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * Git仓库组服务实现
 */
@Slf4j
@Service
public class RepositoryGroupServiceImpl extends BaseServiceImpl<RepositoryGroup, RepositoryGroupDTO, RepositoryGroupQuery, Long> implements IRepositoryGroupService {

    @Resource
    private IExternalSystemRepository externalSystemRepository;

    @Resource
    private IRepositoryGroupRepository repositoryGroupRepository;

    @Resource
    private IRepositoryProjectRepository repositoryProjectRepository;

    @Resource
    private IGitServiceIntegration gitServiceIntegration;

    @Resource
    private RepositoryGroupConverter repositoryGroupConverter;

    @Resource
    private IRepositorySyncHistoryService repositorySyncHistoryService;

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

    @Override
    @Async
    @Transactional(rollbackFor = Exception.class)
    public void syncGroups(Long externalSystemId) {
        // 尝试获取锁
        if (!syncLockManager.tryLock(externalSystemId)) {
            return;
        }

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

    private void doSyncGroups(Long externalSystemId) {
        // 1. 创建同步历史记录
        RepositorySyncHistoryDTO groupHistory = repositorySyncHistoryService.createSyncHistory(externalSystemId, RepositorySyncType.GROUP);

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

            // 3. 从Git API获取所有仓库组信息
            List<GitGroupResponse> remoteGroups = gitServiceIntegration.groups(externalSystem);
            if (remoteGroups.isEmpty()) {
                log.debug("No groups found in remote git system: {}", externalSystem.getName());
                repositorySyncHistoryService.updateSyncHistory(groupHistory.getId(), ExternalSystemSyncStatus.SUCCESS, null);
                return;
            }

            // 4. 获取本地已存在的仓库组
            List<RepositoryGroup> existingGroups = repositoryGroupRepository.findByExternalSystemIdAndDeletedFalse(externalSystemId);
            Map<Long, RepositoryGroup> existingGroupMap = existingGroups.stream()
                .collect(Collectors.toMap(RepositoryGroup::getRepoGroupId, Function.identity()));

            // 5. 处理每个远程仓库组
            List<RepositoryGroup> groupsToSave = new ArrayList<>();
            for (GitGroupResponse remoteGroup : remoteGroups) {
                RepositoryGroup group = existingGroupMap.getOrDefault(remoteGroup.getId(), new RepositoryGroup());
                
                // 更新基本信息
                group.setExternalSystemId(externalSystemId);
                group.setRepoGroupId(remoteGroup.getId());
                group.setName(remoteGroup.getName());
                group.setPath(remoteGroup.getPath());
                group.setDescription(remoteGroup.getDescription());
                group.setVisibility(remoteGroup.getVisibility());
                group.setWebUrl(remoteGroup.getWebUrl());
                group.setAvatarUrl(remoteGroup.getAvatarUrl());
                group.setParentId(remoteGroup.getParentId());
                
                // 设置完整名称和路径
                group.setFullName(remoteGroup.getFullName());
                group.setFullPath(remoteGroup.getFullPath());
                
                groupsToSave.add(group);
            }

            // 6. 保存所有仓库组
            List<RepositoryGroup> savedGroups = repositoryGroupRepository.saveAll(groupsToSave);
            
            // 7. 更新同步历史记录为成功
            repositorySyncHistoryService.updateSyncHistory(groupHistory.getId(), ExternalSystemSyncStatus.SUCCESS, null);
            
            log.info("Successfully synchronized {} groups for external system: {}", 
                savedGroups.size(), externalSystem.getName());
            
        } catch (Exception e) {
            // 8. 更新同步历史记录为失败
            repositorySyncHistoryService.updateSyncHistory(groupHistory.getId(), ExternalSystemSyncStatus.FAILED, e.getMessage());
            log.error("Failed to sync repository groups for external system: {}", externalSystemId, e);
            throw new BusinessException(ResponseCode.REPOSITORY_GROUP_SYNC_FAILED);
        }
    }

    @Override
    public Long countByExternalSystemId(Long externalSystemId) {
        return repositoryGroupRepository.countByExternalSystemId(externalSystemId);
    }

    @Override
    public List<RepositoryGroupDTO> findByExternalSystemId(Long externalSystemId) {
        return repositoryGroupConverter.toDtoList(repositoryGroupRepository.findByExternalSystemId(externalSystemId));
    }

    @Override
    public Page<RepositoryGroupDTO> page(RepositoryGroupQuery query) {
        Page<RepositoryGroupDTO> page = super.page(query);
        fillProjectCounts(page.getContent());
        return page;
    }

    @Override
    public List<RepositoryGroupDTO> findAll(RepositoryGroupQuery query) {
        List<RepositoryGroupDTO> list = super.findAll(query);
        fillProjectCounts(list);
        return list;
    }
    
    /**
     * 批量填充仓库组的项目数量（解决N+1查询问题）
     */
    private void fillProjectCounts(List<RepositoryGroupDTO> groups) {
        if (groups.isEmpty()) {
            return;
        }
        
        // 1. 收集所有仓库组的repoGroupId
        Set<Long> repoGroupIds = groups.stream()
            .map(RepositoryGroupDTO::getRepoGroupId)
            .collect(Collectors.toSet());
        
        // 2. 批量查询项目数量（1条SQL）
        List<Object[]> countResults = repositoryProjectRepository.countByRepoGroupIds(repoGroupIds);
        Map<Long, Long> projectCountMap = countResults.stream()
            .collect(Collectors.toMap(
                arr -> (Long) arr[0],  // repoGroupId
                arr -> (Long) arr[1]   // count
            ));
        
        // 3. 填充数据
        groups.forEach(group -> {
            Long projectCount = projectCountMap.getOrDefault(group.getRepoGroupId(), 0L);
            group.setProjectCount(projectCount);
        });
    }
} 