package com.ruoyi.platform.service.impl;

import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.platform.domain.ActiveLearn;
import com.ruoyi.platform.domain.ActiveLearnIns;
import com.ruoyi.platform.mapper.ActiveLearnDao;
import com.ruoyi.platform.mapper.ActiveLearnInsDao;
import com.ruoyi.platform.service.ActiveLearnInsService;
import com.ruoyi.platform.service.ActiveLearnService;
import com.ruoyi.platform.service.ResourceOccupyService;
import com.ruoyi.platform.utils.HttpUtils;
import com.ruoyi.platform.utils.JacksonUtil;
import com.ruoyi.platform.utils.JsonUtils;
import com.ruoyi.platform.vo.ActiveLearnParamVo;
import com.ruoyi.platform.vo.ActiveLearnVo;
import com.ruoyi.system.api.constant.Constant;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

@Service
public class ActiveLearnServiceImpl implements ActiveLearnService {
    @Value("${argo.url}")
    private String argoUrl;
    @Value("${argo.workflowRun}")
    private String argoWorkflowRun;
    @Value("${argo.convertActiveLearn}")
    String convertActiveLearn;

    @Resource
    private ResourceOccupyService resourceOccupyService;

    @Resource
    private ActiveLearnDao activeLearnDao;
    @Resource
    private ActiveLearnInsDao activeLearnInsDao;
    @Resource
    private ActiveLearnInsService activeLearnInsService;


    @Override
    public Page<ActiveLearn> queryByPage(String name, PageRequest pageRequest) {
        long total = activeLearnDao.count(name);
        List<ActiveLearn> activeLearns = activeLearnDao.queryByPage(name, pageRequest);
        return new PageImpl<>(activeLearns, pageRequest, total);
    }

    @Override
    public ActiveLearn save(ActiveLearnVo activeLearnVo) throws Exception {
        if (activeLearnVo.getName().length() > 64) {
            throw new RuntimeException("实验名称大于最大长度");
        }
        ActiveLearn activeLearnByName = activeLearnDao.getActiveLearnByName(activeLearnVo.getName());
        if (activeLearnByName != null) {
            throw new RuntimeException("实验名称已存在");
        }

        ActiveLearn activeLearn = new ActiveLearn();
        BeanUtils.copyProperties(activeLearnVo, activeLearn);
        String username = SecurityUtils.getLoginUser().getUsername();
        activeLearn.setCreateBy(username);
        activeLearn.setUpdateBy(username);
        activeLearn.setDataset(JacksonUtil.toJSONString(activeLearnVo.getDataset()));
        activeLearn.setCodeConfig(JacksonUtil.toJSONString(activeLearnVo.getCodeConfig()));
        activeLearn.setModel(JacksonUtil.toJSONString(activeLearnVo.getModel()));
        activeLearn.setImage(JacksonUtil.toJSONString(activeLearnVo.getImage()));
        activeLearnDao.save(activeLearn);
        return activeLearn;
    }

    @Override
    public String edit(ActiveLearnVo activeLearnVo) throws Exception {
        ActiveLearn oldActiveLearn = activeLearnDao.getActiveLearnByName(activeLearnVo.getName());
        if (oldActiveLearn != null && !oldActiveLearn.getId().equals(activeLearnVo.getId())) {
            throw new RuntimeException("实验名称已存在");
        }
        ActiveLearn activeLearn = new ActiveLearn();
        BeanUtils.copyProperties(activeLearnVo, activeLearn);
        activeLearn.setUpdateBy(SecurityUtils.getLoginUser().getUsername());
        activeLearn.setDataset(JacksonUtil.toJSONString(activeLearnVo.getDataset()));
        activeLearn.setCodeConfig(JacksonUtil.toJSONString(activeLearnVo.getCodeConfig()));
        activeLearn.setModel(JacksonUtil.toJSONString(activeLearnVo.getModel()));
        activeLearn.setImage(JacksonUtil.toJSONString(activeLearnVo.getImage()));
        activeLearnDao.edit(activeLearn);
        return "修改成功";
    }

    @Override
    public ActiveLearnVo getActiveLearnDetail(Long id) throws IOException {
        ActiveLearn activeLearn = activeLearnDao.getActiveLearnById(id);
        ActiveLearnVo activeLearnVo = new ActiveLearnVo();
        BeanUtils.copyProperties(activeLearn, activeLearnVo);
        if (StringUtils.isNotEmpty(activeLearn.getDataset())) {
            activeLearnVo.setDataset(JsonUtils.jsonToMap(activeLearn.getDataset()));
        }
        if (StringUtils.isNotEmpty(activeLearn.getCodeConfig())) {
            activeLearnVo.setCodeConfig(JsonUtils.jsonToMap(activeLearn.getCodeConfig()));
        }
        if (StringUtils.isNotEmpty(activeLearn.getModel())) {
            activeLearnVo.setModel(JsonUtils.jsonToMap(activeLearn.getModel()));
        }
        if (StringUtils.isNotEmpty(activeLearn.getImage())) {
            activeLearnVo.setImage(JsonUtils.jsonToMap(activeLearn.getImage()));
        }
        return activeLearnVo;
    }

    @Override
    @Transactional
    public String delete(Long id) throws Exception {
        ActiveLearn activeLearn = activeLearnDao.getActiveLearnById(id);
        if (activeLearn == null) {
            throw new Exception("实验不存在");
        }
        String username = SecurityUtils.getLoginUser().getUsername();
        String createBy = activeLearn.getCreateBy();
        if (!(StringUtils.equals(username, "admin") || StringUtils.equals(username, createBy))) {
            throw new Exception("无权限删除该实验");
        }

        List<ActiveLearnIns> insList = activeLearnInsDao.getByActiveLearnId(id);
        if (!insList.isEmpty()) {
            throw new Exception("该实验存在实例，无法删除");
        }
        activeLearn.setState(Constant.State_invalid);
        resourceOccupyService.deleteTaskState(Constant.TaskType_ActiveLearn, id, null);
        return activeLearnDao.edit(activeLearn) > 0 ? "删除成功" : "删除失败";
    }

    @Override
    public String runActiveLearnIns(Long id) throws Exception {
        ActiveLearn activeLearn = activeLearnDao.getActiveLearnById(id);
        if (activeLearn == null) {
            throw new Exception("主动学习配置不存在");
        }

        // 记录开始扣积分
        if (resourceOccupyService.haveResource(activeLearn.getComputingResourceId(), 1)) {
            ActiveLearnParamVo activeLearnParamVo = new ActiveLearnParamVo();
            BeanUtils.copyProperties(activeLearn, activeLearnParamVo);
            activeLearnParamVo.setCodeConfig(JsonUtils.jsonToMap(activeLearn.getCodeConfig()));
            activeLearnParamVo.setDataset(JsonUtils.jsonToMap(activeLearn.getDataset()));
            activeLearnParamVo.setModel(JsonUtils.jsonToMap(activeLearn.getModel()));
            activeLearnParamVo.setImage(JsonUtils.jsonToMap(activeLearn.getImage()));
            activeLearnParamVo.setExperimentInsId(String.valueOf(UUID.randomUUID()).replace("-", "").substring(0, 24));
            String param = JsonUtils.getConvertParam(activeLearnParamVo);

            // 调argo转换接口
            try {
                String convertRes = HttpUtils.sendPost(argoUrl + convertActiveLearn, param);
                if (convertRes == null || StringUtils.isEmpty(convertRes)) {
                    throw new RuntimeException("转换流水线失败");
                }
                Map<String, Object> converMap = JsonUtils.jsonToMap(convertRes);
                if (converMap.get("data") == null) {
                    throw new RuntimeException("转换流水线失败");
                }

                // 组装运行接口json
                Map<String, Object> output = (Map<String, Object>) converMap.get("output");
                Map<String, Object> runReqMap = new HashMap<>();
                runReqMap.put("data", converMap.get("data"));
                // 调argo运行接口
                String runRes = HttpUtils.sendPost(argoUrl + argoWorkflowRun, JsonUtils.mapToJson(runReqMap));
                if (runRes == null || StringUtils.isEmpty(runRes)) {
                    throw new RuntimeException("运行失败");
                }
                Map<String, Object> runResMap = JsonUtils.jsonToMap(runRes);
                Map<String, Object> data = (Map<String, Object>) runResMap.get("data");
                //判断data为空
                if (data == null || MapUtils.isEmpty(data)) {
                    throw new RuntimeException("运行失败");
                }
                Map<String, Object> metadata = (Map<String, Object>) data.get("metadata");

                // 插入记录到实验实例表
                ActiveLearnIns activeLearnIns = new ActiveLearnIns();
                activeLearnIns.setActiveLearnId(id);
                activeLearnIns.setArgoInsNs((String) metadata.get("namespace"));
                activeLearnIns.setArgoInsName((String) metadata.get("name"));
                activeLearnIns.setParam(param);
                activeLearnIns.setStatus(Constant.Pending);
                //替换argoInsName
                String outputString = JsonUtils.mapToJson(output);
                activeLearnIns.setNodeResult(outputString.replace("{{workflow.name}}", (String) metadata.get("name")));

                Map<String, Object> param_output = (Map<String, Object>) output.get("param_output");
                List output1 = (ArrayList) param_output.values().toArray()[0];
                Map<String, String> output2 = (Map<String, String>) output1.get(0);
                String outputPath = output2.get("path").replace("{{workflow.name}}", (String) metadata.get("name"));
                activeLearnIns.setResultPath(outputPath);
                activeLearnInsDao.insert(activeLearnIns);
                activeLearnInsService.updateActiveLearnStatus(id);
                // 记录开始扣除积分
                resourceOccupyService.startDeduce(activeLearn.getComputingResourceId(), 1, Constant.TaskType_ActiveLearn, id, activeLearnIns.getId(), null, activeLearn.getName(), null, null);
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage());
            }
        }
        return "执行成功";
    }
}
