package cn.reghao.autodop.dmaster.app.service.config.impl;

import cn.reghao.autodop.dmaster.app.db.crud.config.AppConfigCrud;
import cn.reghao.autodop.dmaster.app.db.query.config.AppConfigQuery;
import cn.reghao.autodop.dmaster.app.db.repository.AppRunningRepository;
import cn.reghao.autodop.dmaster.app.model.dto.DeployConfigDto;
import cn.reghao.autodop.dmaster.app.model.po.AppRunning;
import cn.reghao.autodop.dmaster.app.model.po.config.AppConfig;
import cn.reghao.autodop.dmaster.app.model.po.config.DeployConfig;
import cn.reghao.autodop.dmaster.app.model.dto.NewApp;
import cn.reghao.autodop.dmaster.app.model.po.config.build.PackerConfig;
import cn.reghao.autodop.dmaster.app.service.impl.BuildDeployConfigServiceImpl;
import cn.reghao.autodop.dmaster.app.service.config.AppConfigService;
import cn.reghao.autodop.dmaster.machine.db.query.MachineHostQuery;
import cn.reghao.autodop.dmaster.notification.model.po.NotifyGroup;
import cn.reghao.jdkutil.result.Result;
import cn.reghao.jdkutil.result.ResultStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author reghao
 * @date 2021-09-16 18:28:51
 */
@Service
public class AppConfigServiceImpl implements AppConfigService {
    private final AppConfigQuery appConfigQuery;
    private final AppConfigCrud appConfigCrud;
    private final MachineHostQuery machineHostQuery;
    private final SharedEntityChecker sharedEntityChecker;
    private final BuildDeployConfigServiceImpl appBuildService;
    private final AppRunningRepository runningRepository;

    public AppConfigServiceImpl(AppConfigQuery appConfigQuery, AppConfigCrud appConfigCrud,
                                MachineHostQuery machineHostQuery, SharedEntityChecker sharedEntityChecker,
                                BuildDeployConfigServiceImpl appBuildService, AppRunningRepository runningRepository) {
        this.appConfigQuery = appConfigQuery;
        this.appConfigCrud = appConfigCrud;
        this.machineHostQuery = machineHostQuery;
        this.sharedEntityChecker = sharedEntityChecker;
        this.appBuildService = appBuildService;
        this.runningRepository = runningRepository;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result add(AppConfig app) {
        // TODO 处理所有与 app 关联的数据
        // TODO 不能有应用处于构建中
        // 首先处理共享实体，将 app 的所有属性填充完整
        try {
            checkSharedEntity(app);
        } catch (Exception e) {
            return Result.fail(e.getMessage());
        }

        appConfigCrud.save(app);
        appBuildService.refreshAppBuilding(app);
        String msg = String.format("添加 %s 成功", app.getAppId());
        return Result.result(ResultStatus.SUCCESS, msg);
    }

    private void checkSharedEntity(AppConfig app) throws Exception {
        sharedEntityChecker.checkAndSetBuildConfig(app);
    }

    @Override
    public Result setDeployConfig(int id, List<DeployConfigDto> deployConfigDtos) {
        AppConfig app = appConfigQuery.findById(id);
        if (app == null) {
            return Result.fail(String.format("id %s 不存在", id));
        }

        PackerConfig packerConfig = app.getPackerConfig();
        String packType = packerConfig.getType();
        List<DeployConfig> list = deployConfigDtos.stream()
                .map(deployConfigDto -> {
                    String machineId = deployConfigDto.getMachineId();
                    String machineIpv4 = machineHostQuery.findByMachineId(machineId).getMachineIpv4();
                    String startScript = deployConfigDto.getStartScript();
                    return new DeployConfig(machineId, machineIpv4, packType, startScript);
                })
                .collect(Collectors.toList());

        app.setDeployConfigs(list);
        appConfigCrud.save(app);
        return Result.result(ResultStatus.SUCCESS);
    }

    @Override
    public Result setNotify(int id, List<NotifyGroup> notifyGroups) {
        AppConfig app = appConfigQuery.findById(id);
        if (app == null) {
            return Result.fail(String.format("id %s 不存在", id));
        }

        app.setNotifyGroups(notifyGroups);
        appConfigCrud.save(app);
        return Result.result(ResultStatus.SUCCESS);
    }

    @Override
    public Result copy(AppConfig from, NewApp to) {
        if (from == null) {
            return Result.result(ResultStatus.FAIL, "AppConfig 不存在");
        }

        AppConfig toApp = appConfigQuery.findByIsDeleteFalseAndAppId(to.getNewId());
        if (toApp != null) {
            String msg = String.format("%s 已存在", to.getNewId());
            return Result.result(ResultStatus.FAIL, msg);
        }

        try {
            toApp = to.app((AppConfig) from.clone());
            return add(toApp);
        } catch (CloneNotSupportedException e) {
            return Result.fail(e.getMessage());
        }
    }

    @Override
    public Result modify(AppConfig app) {
        // TODO 处理所有与 app 关联的数据
        // TODO 不能有应用处于构建中
        // 首先处理共享实体，将 app 的所有属性填充完整
        try {
            checkSharedEntity(app);
        } catch (Exception e) {
            return Result.fail(e.getMessage());
        }

        appConfigCrud.save(app);
        appBuildService.refreshAppBuilding(app);

        String msg = String.format("更新 %s 成功", app.getAppId());
        return Result.result(ResultStatus.SUCCESS, msg);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result delete(AppConfig app) {
        String appId = app.getAppId();
        List<AppRunning> appRunnings = runningRepository.findByAppId(appId).stream()
                .filter(AppRunning::getIsRunning).collect(Collectors.toList());
        if (!appRunnings.isEmpty()) {
            return Result.result(ResultStatus.FAIL, appId + " 正在运行中");
        }

        // TODO 处理所有与 app 关联的数据
        appBuildService.delete(app.getAppId());
        appConfigCrud.delete(app);
        return Result.result(ResultStatus.SUCCESS);
    }
}
