package cn.reghao.bnt.web.devops.app.db.query.impl;

import cn.reghao.bnt.web.devops.app.db.query.AppBuildQuery;
import cn.reghao.bnt.web.devops.app.db.query.AppDeployQuery;
import cn.reghao.bnt.web.devops.app.db.repository.AppBuildingRepository;
import cn.reghao.bnt.web.devops.app.db.repository.config.AppConfigRepository;
import cn.reghao.bnt.web.devops.app.db.repository.log.BuildLogRepository;
import cn.reghao.bnt.web.devops.app.model.po.AppBuilding;
import cn.reghao.bnt.web.devops.app.model.po.config.AppConfig;
import cn.reghao.bnt.web.devops.app.model.po.log.BuildLog;
import cn.reghao.bnt.web.devops.app.model.vo.AppBuildingVO;
import cn.reghao.bnt.web.devops.app.model.vo.AppConfigVO;
import cn.reghao.bnt.web.devops.app.model.vo.BuildLogVO;
import cn.reghao.bnt.web.devops.build.model.po.CompilerConfig;
import cn.reghao.bnt.web.devops.build.model.po.PackerConfig;
import cn.reghao.bnt.web.devops.build.model.po.RepoAuthConfig;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import jakarta.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author reghao
 * @date 2021-06-02 15:01:18
 */
@Service
public class AppBuildQueryImpl implements AppBuildQuery {
    private final AppConfigRepository appConfigRepository;
    private final AppBuildingRepository buildingRepository;
    private final BuildLogRepository buildLogRepository;
    private final AppDeployQuery appDeployQuery;

    public AppBuildQueryImpl(AppConfigRepository appConfigRepository, AppBuildingRepository buildingRepository,
                             BuildLogRepository buildLogRepository, AppDeployQuery appDeployQuery) {
        this.appConfigRepository = appConfigRepository;
        this.buildingRepository = buildingRepository;
        this.buildLogRepository = buildLogRepository;
        this.appDeployQuery = appDeployQuery;
    }

    @Override
    public Page<AppConfig> queryByFields(Map<String, String> kv, Pageable pageable) {
        Specification<AppConfig> specification = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            kv.forEach((name, value) -> {
                predicates.add(cb.like(root.get(name), "%" + value + "%"));
            });

            // select * from app_building where app_id like '%test%' and app_name like '%测试%'
            return cb.and(predicates.toArray(new Predicate[0]));
        };
        
        return appConfigRepository.findAll(specification, pageable);
    }

    @Override
    public AppConfig getByRepoAndBranch(String repo, String branch) {
        List<AppConfig> list = appConfigRepository.findByAppRepoAndRepoBranch(repo, branch);
        return list.size() == 1 ? list.get(0) : null;
    }

    //@Cacheable({"appId"})
    @Override
    public AppConfig getAppConfig(String appId) {
        return appConfigRepository.findByDeletedFalseAndAppId(appId);
    }

    @Override
    public Page<AppConfigVO> getByEnvAndType(String env, String type, Pageable pageable) {
        Page<AppConfig> page = appConfigRepository.findByEnvAndAppType(env, type, pageable);
        List<AppConfigVO> list = page.stream()
                .map(appConfig -> {
                    int totalDeployNodes = appDeployQuery.countByApp(appConfig);
                    int totalDomains = 0;
                    String domains = appConfig.getDomains();
                    if (domains != null) {
                        totalDomains = domains.split(",").length;
                    }
                    return new AppConfigVO(appConfig, totalDeployNodes, totalDomains);
                })
                .collect(Collectors.toList());
        return new PageImpl<>(list, page.getPageable(), page.getTotalElements());
    }

    @Override
    public List<AppConfig> findAllByRepoAuthConfig(RepoAuthConfig repoAuthConfig) {
        return appConfigRepository.findAllByRepoAuthConfig(repoAuthConfig);
    }

    @Override
    public List<AppConfig> findAllByCompilerConfig(CompilerConfig compilerConfig) {
        return appConfigRepository.findAllByCompilerConfig(compilerConfig);
    }

    @Override
    public List<AppConfig> findAllByPackerConfig(PackerConfig packerConfig) {
        return appConfigRepository.findAllByPackerConfig(packerConfig);
    }

    @Override
    public Page<AppBuildingVO> getByPage(String appEnv, String appType, Pageable pageable) {
        Page<AppBuilding> page = buildingRepository.findAllByAppConfig_EnvAndAppConfig_AppType(appEnv, appType, pageable);
        Page<AppBuildingVO> page1 = page.map(appBuilding -> {
            int totalNode = appDeployQuery.countByApp(appBuilding.getAppConfig());
            int totalRunning = 0;
            BuildLog buildLog = appBuilding.getBuildLog();
            if (buildLog != null) {
                String buildLogId = buildLog.getBuildLogId();
                totalRunning = appDeployQuery.getAppRunningCountByBuildLogId(buildLogId);
            }

            return new AppBuildingVO(appBuilding, totalNode, totalRunning);
        });
        return page1;
    }

    @Override
    public boolean isBuilding(String appId) {
        AppBuilding appBuilding1 = buildingRepository.findAllByAppConfig_AppId(appId);
        if (appBuilding1 == null) {
            return false;
        }

        return appBuilding1.isOnBuilding();
    }

    @Deprecated
    public AppBuilding getAppBuilding(String appId) {
        AppBuilding appBuilding1 = buildingRepository.findAllByAppConfig_AppId(appId);
        return appBuilding1;
    }

    @Override
    public Page<BuildLogVO> buildLogVOs(String appId, Pageable pageable) {
        AppConfig appConfig = appConfigRepository.findByAppId(appId);
        return buildLogRepository.findByAppConfig(appConfig, pageable).map(BuildLogVO::new);
    }

    @Override
    public BuildLog getBuildLog(String buildLogId) {
        return buildLogRepository.findByBuildLogId(buildLogId);
    }

    @Override
    public String getBuildResult(String buildLogId) {
        BuildLog buildLog = buildLogRepository.findByBuildLogId(buildLogId);
        if (buildLog != null) {
            return buildLog.getMsg();
        }
        return "";
    }
}
