package com.ruoyi.platform.service.impl;

import com.ruoyi.platform.constant.Constant;
import com.ruoyi.platform.domain.AutoMl;
import com.ruoyi.platform.domain.AutoMlIns;
import com.ruoyi.platform.mapper.AutoMlDao;
import com.ruoyi.platform.mapper.AutoMlInsDao;
import com.ruoyi.platform.service.AutoMlInsService;
import com.ruoyi.platform.utils.DateUtils;
import com.ruoyi.platform.utils.HttpUtils;
import com.ruoyi.platform.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
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 javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

@Service
public class AutoMlInsServiceImpl implements AutoMlInsService {
    @Value("${argo.url}")
    private String argoUrl;
    @Value("${argo.workflowStatus}")
    private String argoWorkflowStatus;
    @Value("${argo.workflowTermination}")
    private String argoWorkflowTermination;

    @Resource
    private AutoMlInsDao autoMlInsDao;
    @Resource
    private AutoMlDao autoMlDao;

    @Override
    public Page<AutoMlIns> queryByPage(AutoMlIns autoMlIns, PageRequest pageRequest) throws IOException {
        long total = this.autoMlInsDao.count(autoMlIns);
        List<AutoMlIns> autoMlInsList = this.autoMlInsDao.queryAllByLimit(autoMlIns, pageRequest);
        return new PageImpl<>(autoMlInsList, pageRequest, total);
    }

    @Override
    public AutoMlIns insert(AutoMlIns autoMlIns) {
        this.autoMlInsDao.insert(autoMlIns);
        return autoMlIns;
    }

    @Override
    public String removeById(Long id) {
        AutoMlIns autoMlIns = autoMlInsDao.queryById(id);
        if (autoMlIns == null) {
            return "实验实例不存在";
        }

        if (StringUtils.isEmpty(autoMlIns.getStatus())) {
            autoMlIns = queryStatusFromArgo(autoMlIns);
        }
        if (StringUtils.equals(autoMlIns.getStatus(), Constant.Running)) {
            return "实验实例正在运行，不可删除";
        }

        autoMlIns.setState(Constant.State_invalid);
        int update = autoMlInsDao.update(autoMlIns);
        if (update > 0) {
            updateAutoMlStatus(autoMlIns.getAutoMlId());
            return "删除成功";
        } else {
            return "删除失败";
        }
    }

    @Override
    public String batchDelete(List<Long> ids) {
        for (Long id : ids) {
            String result = removeById(id);
            if (!"删除成功".equals(result)) {
                return result;
            }
        }
        return "删除成功";
    }

    @Override
    public List<AutoMlIns> queryByAutoMlInsIsNotTerminated() {
        return autoMlInsDao.queryByAutoMlInsIsNotTerminated();
    }

    @Override
    public AutoMlIns queryStatusFromArgo(AutoMlIns ins) {
        String namespace = ins.getArgoInsNs();
        String name = ins.getArgoInsName();

        // 创建请求数据map
        Map<String, Object> requestData = new HashMap<>();
        requestData.put("namespace", namespace);
        requestData.put("name", name);

        // 创建发送数据map，将请求数据作为"data"键的值
        Map<String, Object> res = new HashMap<>();
        res.put("data", requestData);

        try {
            // 发送POST请求到Argo工作流状态查询接口，并将请求数据转换为JSON
            String req = HttpUtils.sendPost(argoUrl + argoWorkflowStatus, null, JsonUtils.mapToJson(res));
            // 检查响应是否为空或无内容
            if (req == null || StringUtils.isEmpty(req)) {
                throw new RuntimeException("工作流状态响应为空。");
            }
            // 将响应的JSON字符串转换为Map对象
            Map<String, Object> runResMap = JsonUtils.jsonToMap(req);
            // 从响应Map中获取"data"部分
            Map<String, Object> data = (Map<String, Object>) runResMap.get("data");
            if (data == null || data.isEmpty()) {
                throw new RuntimeException("工作流数据为空.");
            }
            // 从"data"中获取"status"部分，并返回"phase"的值
            Map<String, Object> status = (Map<String, Object>) data.get("status");
            if (status == null || status.isEmpty()) {
                throw new RuntimeException("工作流状态为空。");
            }

            //解析流水线结束时间
            String finishedAtString = (String) status.get("finishedAt");
            if (finishedAtString != null && !finishedAtString.isEmpty()) {
                Date finishTime = DateUtils.convertUTCtoShanghaiDate(finishedAtString);
                ins.setFinishTime(finishTime);
            }

            // 解析nodes字段,提取节点状态并转换为JSON字符串
            Map<String, Object> nodes = (Map<String, Object>) status.get("nodes");
            Map<String, Object> modifiedNodes = new LinkedHashMap<>();
            if (nodes != null) {
                for (Map.Entry<String, Object> nodeEntry : nodes.entrySet()) {
                    Map<String, Object> nodeDetails = (Map<String, Object>) nodeEntry.getValue();
                    String templateName = (String) nodeDetails.get("displayName");
                    modifiedNodes.put(templateName, nodeDetails);
                }
            }

            String nodeStatusJson = JsonUtils.mapToJson(modifiedNodes);
            ins.setNodeStatus(nodeStatusJson);

            //终止态为终止不改
            if (!StringUtils.equals(ins.getStatus(), Constant.Terminated)) {
                ins.setStatus(StringUtils.isNotEmpty((String) status.get("phase")) ? (String) status.get("phase") : Constant.Pending);
            }
            if (StringUtils.equals(ins.getStatus(), "Error")) {
                ins.setStatus(Constant.Failed);
            }
            return ins;
        } catch (Exception e) {
            throw new RuntimeException("查询状态失败: " + e.getMessage(), e);
        }
    }

    @Override
    public boolean terminateAutoMlIns(Long id) throws Exception {
        AutoMlIns autoMlIns = autoMlInsDao.queryById(id);
        if (autoMlIns == null) {
            throw new IllegalStateException("实验实例未查询到，id: " + id);
        }

        String currentStatus = autoMlIns.getStatus();
        String name = autoMlIns.getArgoInsName();
        String namespace = autoMlIns.getArgoInsNs();

        // 获取当前状态，如果为空，则从Argo查询
        if (StringUtils.isEmpty(currentStatus)) {
            currentStatus = queryStatusFromArgo(autoMlIns).getStatus();
        }
        // 只有状态是"Running"时才能终止实例
        if (!currentStatus.equalsIgnoreCase(Constant.Running)) {
            throw new Exception("终止错误，只有运行状态的实例才能终止"); // 如果不是"Running"状态，则不执行终止操作
        }

        // 创建请求数据map
        Map<String, Object> requestData = new HashMap<>();
        requestData.put("namespace", namespace);
        requestData.put("name", name);
        // 创建发送数据map，将请求数据作为"data"键的值
        Map<String, Object> res = new HashMap<>();
        res.put("data", requestData);

        try {
            // 发送POST请求到Argo工作流状态查询接口，并将请求数据转换为JSON
            String req = HttpUtils.sendPost(argoUrl + argoWorkflowTermination, null, JsonUtils.mapToJson(res));
            // 检查响应是否为空或无内容
            if (StringUtils.isEmpty(req)) {
                throw new RuntimeException("终止响应内容为空。");

            }
            // 将响应的JSON字符串转换为Map对象
            Map<String, Object> runResMap = JsonUtils.jsonToMap(req);
            // 从响应Map中直接获取"errCode"的值
            Integer errCode = (Integer) runResMap.get("errCode");
            if (errCode != null && errCode == 0) {
                //更新autoMlIns,确保状态更新被保存到数据库
                AutoMlIns ins = queryStatusFromArgo(autoMlIns);
                String nodeStatus = ins.getNodeStatus();
                Map<String, Object> nodeMap = JsonUtils.jsonToMap(nodeStatus);

                // 遍历 map
                for (Map.Entry<String, Object> entry : nodeMap.entrySet()) {
                    // 获取每个 Map 中的值并强制转换为 Map
                    Map<String, Object> innerMap = (Map<String, Object>) entry.getValue();
                    // 检查 phase 的值
                    if (innerMap.containsKey("phase")) {
                        String phaseValue = (String) innerMap.get("phase");
                        // 如果值不等于 Succeeded，则赋值为 Failed
                        if (!StringUtils.equals("Succeeded", phaseValue)) {
                            innerMap.put("phase", "Failed");
                        }
                    }
                }
                ins.setNodeStatus(JsonUtils.mapToJson(nodeMap));
                ins.setStatus(Constant.Terminated);
                ins.setUpdateTime(new Date());
                this.autoMlInsDao.update(ins);
                updateAutoMlStatus(autoMlIns.getAutoMlId());
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            throw new RuntimeException("终止实例错误: " + e.getMessage(), e);
        }
    }

    @Override
    public AutoMlIns getDetailById(Long id) {
        AutoMlIns autoMlIns = this.autoMlInsDao.queryById(id);
        if(Constant.Running.equals(autoMlIns.getStatus()) || Constant.Pending.equals(autoMlIns.getStatus())){
            autoMlIns = queryStatusFromArgo(autoMlIns);
        }
        return autoMlIns;
    }

    public void updateAutoMlStatus(Long autoMlId) {
        List<AutoMlIns> insList = autoMlInsDao.getByAutoMlId(autoMlId);
        List<String> statusList = new ArrayList<>();
        // 更新实验状态列表
        for (int i = 0; i < insList.size(); i++) {
            statusList.add(insList.get(i).getStatus());
        }
        String subStatus = statusList.toString().substring(1, statusList.toString().length() - 1);
        AutoMl autoMl = autoMlDao.getAutoMlById(autoMlId);
        if (!StringUtils.equals(autoMl.getStatusList(), subStatus)) {
            autoMl.setStatusList(subStatus);
            autoMlDao.edit(autoMl);
        }
    }
}
