package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.model.ServerLabelParam;
import com.bocloud.common.exception.BoCloudDBException;
import com.bocloud.common.model.*;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.Label;
import com.bocloud.ims.entity.resource.ResourceEvent;
import com.bocloud.ims.entity.resource.ServerLabel;
import com.bocloud.ims.interfaces.resource.LabelService;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.LabelRepository;
import com.bocloud.ims.repository.resource.ResourceEventRepository;
import com.bocloud.ims.repository.resource.ServerLabelRepository;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Service("labelService")
public class LabelServiceImpl implements LabelService {

    private static final Logger logger = LoggerFactory.getLogger(LabelServiceImpl.class);

    @Autowired
    private LabelRepository labelRepository;
    @Autowired
    private ServerLabelRepository serverLabelRepository;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private ResourceEventRepository resourceEventRepository;

    @Override
    public BocloudResult<GridBean<Label>> list(Pager pager, RequestContext context) {
        List<Label> list = null;
        int total = 0;
        GridBean gridBean = null;
        try {
            List<Param> params = Optional.ofNullable(pager.getParams()).orElse(new ArrayList<>());
            Map<String, String> sorter = Optional.ofNullable(pager.getSorter()).orElse(Maps.newHashMap());
            Boolean simple = Optional.ofNullable(pager.getSimple()).orElse(false);
            Integer page = Optional.ofNullable(pager.getPage()).orElse(1);
            Integer rows = Optional.ofNullable(pager.getRows()).orElse(10);
            total = labelRepository.count(params);
            if (simple) {
                List<Label> beans = this.labelRepository.list(params);
                gridBean = new GridBean(1, 1, total, beans);
            } else {
                list = labelRepository.list(page, rows, params, sorter);
                gridBean = GridHelper.getBean(page, rows, total, list);
            }
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("list label failure:", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult<Label> detail(Long id) {
        try {
            Label label = labelRepository.query(id);
            return new BocloudResult<>(true, label, "查询成功");
        } catch (Exception e) {
            logger.error("Get error message：", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    @Transactional(rollbackFor = BoCloudDBException.class)
    public BocloudResult<Label> create(Label label) {
        String path = Label.class.getSimpleName() + "_create";
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(30, TimeUnit.SECONDS), "请求超时");
            if (labelRepository.exists(label.getName(), label.getContent(), label.getCategory())) {
                return new BocloudResult<>(false, "标签已存在");
            }
            labelRepository.save(label);
            return new BocloudResult<>(true, label, "添加成功");
        } catch (Exception e) {
            logger.error("Create label error:", e);
            return new BocloudResult<>(false, "添加失败");
        }
    }

    @Override
    public BocloudResult<Label> modify(Label label) {
        String path = Label.class.getSimpleName() + "_" + label.getId();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Label oldLabel = this.labelRepository.query(label.getId());
            if (null == oldLabel) {
                logger.warn("Label does not exist!");
                return new BocloudResult<>(false, "数据不存在");
            }
            if (!label.getName().equals(oldLabel.getName())) {
                if (labelRepository.exists(label.getName())) {
                    return new BocloudResult<>(false, "名称已存在");
                }
            }
            oldLabel.setContent(label.getContent());
            oldLabel.setName(label.getName());
            oldLabel.setCategory(label.getCategory());
            this.labelRepository.update(oldLabel);
            return new BocloudResult<>(true, "修改成功");
        } catch (Exception e) {
            logger.error("Modify label error:", e);
            return new BocloudResult<>(false, "修改失败");
        }
    }

    @Override
    public BocloudResult remove(Long id) {
        String path = Label.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Label oldLabel = this.labelRepository.query(id);
            if (null == oldLabel) {
                logger.warn("Label does not exist!");
                return new BocloudResult<>(false, "数据不存在");
            }
            this.labelRepository.remove(id);
            // 删除已经绑定的资源标签
            // processResource(oldLabel);
            return new BocloudResult<>(true, "删除成功");
        } catch (Exception e) {
            logger.error("Remove label error:", e);
            return new BocloudResult<>(false, "删除失败");
        }
    }

    private void processResource(Label oldLabel) {
        try {
            List<String> labelContents = JSON.parseArray(oldLabel.getContent(), String.class);
            if (!ListTool.isEmpty(labelContents)) {
                List<ServerLabel> listAll = serverLabelRepository.listAll();
                if (ListTool.isEmpty(listAll)) {
                    return;
                }
                for (String labelContent : labelContents) {
                    JSONObject object = new JSONObject();
                    object.put("key", oldLabel.getName());
                    object.put("value", labelContent);
                    for (ServerLabel serverLabel : listAll) {
                        List<JSONObject> parseArray = JSON.parseArray(serverLabel.getContent(), JSONObject.class);
                        if (null != parseArray && parseArray.contains(object)) {
                            parseArray.remove(object);
                            serverLabel.setContent(JSON.toJSONString(parseArray));
                            serverLabelRepository.update(serverLabel);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("删除资源标签异常：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult resources(ServerLabelParam serverLabelParam) {
        try {
            ServerLabel serverLabel = serverLabelRepository.listByTarget(serverLabelParam.getTargetId(),
                serverLabelParam.getType(), serverLabelParam.getVendorId());
            if (null != serverLabel) {
                List<JSONObject> parseArray = JSON.parseArray(serverLabel.getContent(), JSONObject.class);
                if (!ListTool.isEmpty(parseArray)) {
                    for (int i = parseArray.size() - 1; i >= 0; i--) {
                        JSONObject jsonObject = parseArray.get(i);
                        String key = jsonObject.getString("key");
                        String value = jsonObject.getString("value");
                        Label label = labelRepository.getLabelByName(key);
                        if (null != label) {
                            List<String> contentArray = JSON.parseArray(label.getContent(), String.class);
                            if (null != contentArray && !contentArray.contains(value)) {
                                parseArray.remove(jsonObject);
                            }
                        } else {
                            parseArray.remove(jsonObject);
                        }
                    }
                    serverLabel.setContent(JSON.toJSONString(parseArray));
                    serverLabelRepository.update(serverLabel);
                }
            }

            return new BocloudResult<>(true, serverLabel, "查询成功");
        } catch (Exception e) {
            logger.error("查询资源标签异常：" + e.getMessage());
            return new BocloudResult<>(false, "查询资源标签异常：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult createResources(ServerLabelParam serverLabelParam, RequestContext context) {
        try {
            if (null == serverLabelParam) {
                return new BocloudResult<>(false, "参数格式错误");
            }
            new Thread(() -> {
                String operate = ".serverlabel";
                Long vendorId = 0L;
                try {
                    List<Long> targetIds = serverLabelParam.getTargetIds();
                    if (!ListTool.isEmpty(targetIds)) {
                        for (Long target : targetIds) {
                            CloudServer cloudServer = cloudServerRepository.query(target);
                            if (null == cloudServer) {
                                logger.error("虚机ID [{}] 不存在", target);
                                continue;
                            }
                            vendorId = cloudServer.getVendorId();
                            saveServerLabel(target, serverLabelParam.getType(), vendorId,
                                serverLabelParam.getResourceLabel(), context);
                        }
                    }
                    Long targetId = serverLabelParam.getTargetId();
                    if (null != targetId) {
                        CloudServer cloudServer = cloudServerRepository.query(targetId);
                        if (null != cloudServer) {
                            vendorId = cloudServer.getVendorId();
                            saveServerLabel(targetId, serverLabelParam.getType(), vendorId,
                                serverLabelParam.getResourceLabel(), context);
                        }
                    }
                    resourceEventPublisher
                        .send(new OperateResult(true, "标签操作成功", operate, MapTools.simpleMap(Common.VENDORID, vendorId),
                            OperateResult.OperateCategory.ResourceEvent, context));
                } catch (Exception e) {
                    resourceEventPublisher.send(new OperateResult(false, "标签操作失败：" + e.getMessage(), operate,
                        MapTools.simpleMap(Common.VENDORID, vendorId), OperateResult.OperateCategory.ResourceEvent,
                        context));
                }
            }).start();
            return new BocloudResult<String>(true, "任务已下发，正在执行...");
        } catch (Exception e) {
            logger.error("资源标签操作异常：" + e.getMessage());
            return new BocloudResult<>(false, "资源标签操作异常：" + e.getMessage());
        }
    }

    public void saveServerLabel(Long targetId, String type, Long vendorId, String content, RequestContext context) {
        try {
            ServerLabel serverLabel = serverLabelRepository.listByTarget(targetId, type, vendorId);
            if (null == serverLabel) {
                serverLabel = new ServerLabel();
                serverLabel.setTarget(targetId);
                serverLabel.setVendorId(vendorId);
                serverLabel.setContent(content);
                serverLabel.setType(type);
                serverLabelRepository.save(serverLabel);
            } else {
                serverLabel.setContent(content);
                serverLabelRepository.update(serverLabel);
            }
            ResourceEvent event = new ResourceEvent(targetId, "虚拟机标签配置", "配置标签成功：" + content, context.getTarget(),
                new Date(), "VM", vendorId, context.getCatalog());
            resourceEventRepository.save(event);
        } catch (Exception e) {
            logger.error("保存资源标签异常：" + e.getMessage());
        }
    }

    public BocloudResult deleteResourceLabel(Long targetId, String type, Long vendorId) {
        String path = Label.class.getSimpleName() + "_" + targetId + "_" + type + "_" + vendorId;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            ServerLabel serverLabel = serverLabelRepository.listByTarget(targetId, type, vendorId);
            if (null != serverLabel) {
                serverLabelRepository.delete(serverLabel.getId());
            }
            return new BocloudResult<>(true, "删除成功");
        } catch (Exception e) {
            logger.error("Remove label error:", e);
            return new BocloudResult<>(false, "删除失败");
        }
    }

}
