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

import com.qqchen.deploy.backend.deploy.converter.ApplicationCategoryConverter;
import com.qqchen.deploy.backend.deploy.converter.ExternalSystemConverter;
import com.qqchen.deploy.backend.deploy.converter.RepositoryProjectConverter;
import com.qqchen.deploy.backend.deploy.dto.ApplicationCategoryDTO;
import com.qqchen.deploy.backend.deploy.dto.ApplicationDTO;
import com.qqchen.deploy.backend.deploy.dto.DevelopmentLanguageTypeDTO;
import com.qqchen.deploy.backend.deploy.dto.RepositoryProjectDTO;
import com.qqchen.deploy.backend.system.model.ExternalSystemDTO;
import com.qqchen.deploy.backend.deploy.entity.Application;
import com.qqchen.deploy.backend.deploy.entity.ApplicationCategory;
import com.qqchen.deploy.backend.deploy.entity.ExternalSystem;
import com.qqchen.deploy.backend.deploy.entity.RepositoryProject;
import com.qqchen.deploy.backend.deploy.enums.DevelopmentLanguageTypeEnum;
import com.qqchen.deploy.backend.deploy.query.ApplicationQuery;
import com.qqchen.deploy.backend.deploy.repository.IApplicationCategoryRepository;
import com.qqchen.deploy.backend.deploy.repository.IApplicationRepository;
import com.qqchen.deploy.backend.deploy.repository.IExternalSystemRepository;
import com.qqchen.deploy.backend.deploy.repository.IRepositoryProjectRepository;
import com.qqchen.deploy.backend.deploy.repository.ITeamApplicationRepository;
import com.qqchen.deploy.backend.deploy.service.IApplicationService;
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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import static java.util.stream.Collectors.toList;

@Slf4j
@Service
public class ApplicationServiceImpl extends BaseServiceImpl<Application, ApplicationDTO, ApplicationQuery, Long> implements IApplicationService {

    @Resource
    private IApplicationCategoryRepository applicationCategoryRepository;

    @Resource
    private ApplicationCategoryConverter applicationCategoryConverter;

    @Resource
    private IRepositoryProjectRepository repositoryProjectRepository;

    @Resource
    private RepositoryProjectConverter repositoryProjectConverter;

    @Resource
    private IApplicationRepository applicationRepository;

    @Resource
    private ITeamApplicationRepository teamApplicationRepository;

    @Resource
    private IExternalSystemRepository externalSystemRepository;

    @Resource
    private ExternalSystemConverter externalSystemConverter;

    /**
     * 填充应用的关联数据（分类和团队数量）
     */
    private void fillApplicationRelations(List<ApplicationDTO> applications) {
        if (applications.isEmpty()) {
            return;
        }

        // 批量查询应用分类
        List<Long> categoryIds = applications.stream()
            .map(ApplicationDTO::getApplicationCategoryId)
            .filter(java.util.Objects::nonNull)
            .distinct()
            .collect(toList());
        java.util.Map<Long, ApplicationCategoryDTO> categoryMap = new java.util.HashMap<>();
        if (!categoryIds.isEmpty()) {
            applicationCategoryRepository.findAllById(categoryIds).forEach(category ->
                categoryMap.put(category.getId(), applicationCategoryConverter.toDto(category))
            );
        }

        // 批量统计团队数量
        List<Long> applicationIds = applications.stream()
            .map(ApplicationDTO::getId)
            .collect(toList());
        java.util.Map<Long, Long> teamCountMap = new java.util.HashMap<>();
        if (!applicationIds.isEmpty()) {
            List<Object[]> teamCountResults = teamApplicationRepository.countDistinctTeamIdByApplicationIds(applicationIds);
            teamCountResults.forEach(result -> {
                Long applicationId = ((Number) result[0]).longValue();
                Long teamCount = ((Number) result[1]).longValue();
                teamCountMap.put(applicationId, teamCount);
            });
        }

        // 设置关联数据
        applications.forEach(application -> {
            if (application.getApplicationCategoryId() != null) {
                application.setApplicationCategory(categoryMap.get(application.getApplicationCategoryId()));
            }
            application.setTeamCount(teamCountMap.getOrDefault(application.getId(), 0L));
        });
    }

    @Override
    public Page<ApplicationDTO> page(ApplicationQuery query) {
        Page<ApplicationDTO> page = super.page(query);
        fillApplicationRelations(page.getContent());
        return page;
    }

    @Override
    public List<ApplicationDTO> findAll(ApplicationQuery query) {
        List<ApplicationDTO> list = super.findAll(query);
        fillApplicationRelations(list);
        return list;
    }


    @Override
    public List<DevelopmentLanguageTypeDTO> getAllDevelopmentLanguageTypes() {
        List<DevelopmentLanguageTypeDTO> result = new ArrayList<>();
        Arrays.stream(DevelopmentLanguageTypeEnum.values()).forEach(developmentLanguageTypeEnum -> {
            DevelopmentLanguageTypeDTO dto = new DevelopmentLanguageTypeDTO();
            dto.setCode(developmentLanguageTypeEnum.name());
            dto.setName(developmentLanguageTypeEnum.getCode());
            result.add(dto);
        });
        return result;
    }

    /**
     * 重写删除方法，删除前校验该应用是否被团队绑定
     * 
     * @param id 应用ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        // 1. 查询应用是否存在
        Application application = applicationRepository.findById(id)
            .orElseThrow(() -> new BusinessException(ResponseCode.ERROR));
        
        // 2. 校验该应用是否被团队绑定
        Long teamCount = teamApplicationRepository.countDistinctTeamIdByApplicationId(id);
        
        if (teamCount != null && teamCount > 0) {
            log.warn("删除应用失败: 应用 {} ({}) 已被 {} 个团队绑定", 
                application.getAppName(), id, teamCount);
            throw new BusinessException(ResponseCode.APPLICATION_HAS_TEAMS, new Object[]{teamCount});
        }
        
        // 3. 执行删除（逻辑删除）
        super.delete(id);
        log.info("成功删除应用: id={}, name={}", id, application.getAppName());
    }

} 