package com.bocloud.ims.service.resource.hmc;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.hmc.HmcVirtualNetworkDriver;
import com.bocloud.cmp.entity.enums.HmcPartitionType;
import com.bocloud.cmp.model.hmc.HmcVirtualSwitchModel;
import com.bocloud.cmp.model.hmc.sdk.module.VirtualSwitchEntry;
import com.bocloud.common.model.*;
import com.bocloud.common.model.OperateResult.OperateCategory;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.JSONTools;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.common.enums.ServerAction;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.ResourceEvent;
import com.bocloud.ims.entity.resource.hmc.HmcPartition;
import com.bocloud.ims.entity.resource.hmc.HmcPartitionNetworkAdapter;
import com.bocloud.ims.entity.resource.hmc.HmcServer;
import com.bocloud.ims.entity.resource.hmc.HmcVirtualSwitch;
import com.bocloud.ims.interfaces.resource.hmc.HmcVirtualSwitchService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.ResourceEventRepository;
import com.bocloud.ims.repository.resource.hmc.*;
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.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Service("hmcVirtualSwitchService")
public class HmcVirtualSwitchServiceImpl implements HmcVirtualSwitchService {
    private static final Logger logger = LoggerFactory.getLogger(HmcProfileServiceImpl.class);
    private static OperateCategory operateCategory = OperateCategory.ResourceEvent;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private HmcVirtualNetworkDriver hmcVirtualNetworkDriver;
    @Autowired
    private HmcVirtualSwitchRepository hmcVirtualSwitchRepository;
    @Autowired
    private HmcServerRepository hmcServerRepository;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private HmcDatabaseHelper hmcDatabaseHelper;
    @Autowired
    private ResourceEventRepository resourceEventRepository;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private HmcProfileNetworkAdapterRepository hmcProfileNetworkAdapterRepository;
    @Autowired
    private HmcPartitionNetworkAdapterRepository hmcPartitionNetworkAdapterRepository;
    @Autowired
    private HmcPartitionRepository hmcPartitionRepository;

    @Override
    public BocloudResult<GridBean<HmcVirtualSwitch>> list(Pager pager) {
        GridBean gridBean = null;
        try {
            int page = pager.getPage();
            int rows = pager.getRows();
            List<Param> params = pager.getParams();
            Map<String, String> sorter = pager.getSorter();
            boolean simple = pager.getSimple();

            if (null == params) {
                return new BocloudResult(false, "参数格式错误");
            }
            // 如果参数中有vendor的信息，需要提取出来单独处理
            Long vendorId = null;
            for (Param param : params) {
                Map<String, Object> paramMap = param.getParam();
                if (paramMap.containsKey("vendorId")) {
                    vendorId = Long.valueOf(paramMap.get("vendorId").toString());
                    paramMap.remove("vendorId");
                }
            }
            if (null == sorter) {
                sorter = Maps.newHashMap();
            }
            int total = this.hmcVirtualSwitchRepository.count(params, vendorId);
            if (simple) {
                sorter.put("switchId", Common.ZERO);
                List<SimpleBean> beans = this.hmcVirtualSwitchRepository.list(params, sorter);
                gridBean = new GridBean(1, 1, total, beans);
            } else {
                sorter.put("gmtCreate", Common.ONE);
                List<HmcVirtualSwitch> list = this.hmcVirtualSwitchRepository.list(page, rows, params, sorter,
                        vendorId);
                gridBean = GridHelper.getBean(page, rows, total, list);
            }
            return new BocloudResult(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("Query partition list fail:", e);
            return new BocloudResult(false, "查询失败");
        }
    }

    @Override
    public BocloudResult create(HmcVirtualSwitch virtualSwitch, RequestContext context) {
        try {
            if (null == virtualSwitch) {
                return new BocloudResult(false, "参数格式错误");
            }
            // 服务器
            Long serverId = virtualSwitch.getServerId();
            HmcServer server = hmcServerRepository.getServerById(serverId);
            if (null == server) {
                logger.error("get HMC server failure!");
                return new BocloudResult(false, "服务器不存在!");
            }

            // 云供应商
            CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
            if (null == vendor) {
                logger.error("get cloudVendor failure!");
                return new BocloudResult(false, "云平台不存在!");
            }

            if (StringUtils.isEmpty(virtualSwitch.getName())) {
                return new BocloudResult(false, "参数name不能为空");
            }
            HmcVirtualSwitch virtualSwitchByName = hmcVirtualSwitchRepository.getByName(virtualSwitch.getName(),
                    virtualSwitch.getServerId());
            if (virtualSwitchByName != null) {
                return new BocloudResult(false, "名称为[" + virtualSwitch.getName() + "]的虚拟交换机已存在");
            }

            // 保存虚拟交换机信息到DB
            virtualSwitch.preSave(context.getTarget(), context.getTarget(), serverId);
            hmcVirtualSwitchRepository.save(virtualSwitch);
            String vendorUuid = vendor.getUuid();
            // 启动一个线程从MQ上获取数据
            taskExecutor.submit(() -> {

                String operate = vendor.getType().toLowerCase() + ".vswitch";
                String content = "虚拟交换机[" + virtualSwitch.getName() + "]创建失败";
                try {
                    ResourceEvent event = null;
                    HmcVirtualSwitchModel virtualSwitchModel = JSON.parseObject(JSON.toJSONString(virtualSwitch), HmcVirtualSwitchModel.class);
                    BocloudResult result = hmcVirtualNetworkDriver.createVirtualSwitch(vendorUuid, virtualSwitchModel,
                            server.getUuid());
                    if (result.isSuccess()) {
                        // update database for the new virtual switch
                        VirtualSwitchEntry entry = (VirtualSwitchEntry) result.getData();
                        hmcDatabaseHelper.updateVirtualSwitch(virtualSwitch, entry, null);
                        content = "虚拟交换机[" + virtualSwitch.getName() + "]创建成功，\n详情：[" + result.getMessage() + "]";
                    } else {
                        hmcVirtualSwitchRepository.remove(virtualSwitch.getId(), context.getTarget());
                        content = "虚拟交换机[" + virtualSwitch.getName() + "]创建失败，\n详情：[" + result.getMessage() + "]";
                        // saveAlarm(partition.getName());
                    }

                    if (result.isSuccess()) {
                        event = new ResourceEvent(virtualSwitch.getId(), ServerAction.CREATE.name(), "成功",
                                context.getTarget(), new Date(), "HMC", vendor.getId(), context.getCatalog());
                    } else {
                        event = new ResourceEvent(virtualSwitch.getId(), ServerAction.CREATE.name(), "失败",
                                context.getTarget(), new Date(), "HMC", vendor.getId(), context.getCatalog());
                    }
                    resourceEventRepository.save(event);
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), operateCategory, context));
                } catch (Exception e) {
                    logger.error("Get Message Exception:", e);
                    resourceEventPublisher.send(new OperateResult(false, content, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), operateCategory, context));
                }

            });
            return new BocloudResult(true, "创建任务已经下发，正在执行……");
        } catch (Exception e) {
            return new BocloudResult(false, "创建失败");
        }
    }

    @Override
    public BocloudResult remove(Long id, RequestContext context) {
        String path = HmcVirtualSwitch.class.getSimpleName() + "_" + id;

        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            if (!lock.acquire(10, TimeUnit.SECONDS)) {
                logger.warn("Get BocloudLock time out!");
                return new BocloudResult(false, "请求超时");
            }
            HmcVirtualSwitch virtualSwitch = hmcVirtualSwitchRepository.getById(id);
            if (null == virtualSwitch) {
                logger.warn("virtual switch data not exist, {}", id);
                return new BocloudResult(false, "数据不存在");
            }
            HmcServer server = hmcServerRepository.getServerById(virtualSwitch.getServerId());
            if (null == server) {
                logger.warn("HMC server data not exist, {}", virtualSwitch.getServerId());
                return new BocloudResult(false, "服务器不存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
            if (null == vendor) {
                logger.error("get cloudVendor failure, {}", server.getVendorId());
                return new BocloudResult(false, "删除失败!");
            }
            taskExecutor.submit(() -> {
                String operate = vendor.getType().toLowerCase() + ".vswitch";
                String content = "虚拟交换机[" + virtualSwitch.getName() + "]删除失败";
                try {
                    ResourceEvent event = null;
                    BocloudResult result = hmcVirtualNetworkDriver.deleteVirtualSwitch(vendor.getUuid(),
                            server.getUuid(), virtualSwitch.getUuid());
                    if (result.isSuccess()) {
                        hmcVirtualSwitchRepository.remove(virtualSwitch.getId(), context.getTarget());
                        event = new ResourceEvent(id, ServerAction.DELETE.name(), "成功", context.getTarget(),
                                new Date(), "HMC虚拟交换机", vendor.getId(), context.getCatalog());
                        content = "虚拟交换机[" + virtualSwitch.getName() + "]删除成功";
                    } else {
                        event = new ResourceEvent(id, ServerAction.DELETE.name(), "失败", context.getTarget(),
                                new Date(), "HMC虚拟交换机", vendor.getId(), context.getCatalog());
                        content = "虚拟交换机[" + virtualSwitch.getName() + "]删除失败,失败原因:[" + result.getMessage() + "]";
                    }
                    resourceEventRepository.save(event);
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), operateCategory, context));
                } catch (Exception e) {
                    logger.error("删除HMC虚拟交换机失败", e);
                    resourceEventPublisher.send(new OperateResult(false, content, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), operateCategory, context));
                }
            });
            return new BocloudResult(true, "删除任务已下发，正在执行...");
        } catch (Exception e) {
            logger.error("remove HMC virtual switch failure:", e);
            return new BocloudResult(false, "删除虚拟交换机失败");
        }
    }

    @Override
    public BocloudResult modify(HmcVirtualSwitch virtualSwitch, RequestContext context) {
        Long virtualSwitchId = virtualSwitch.getId();
        String path = HmcVirtualSwitch.class.getSimpleName() + "_" + virtualSwitchId;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            if (!lock.acquire(10, TimeUnit.SECONDS)) {
                logger.warn("Get BocloudLock time out!");
                return new BocloudResult(false, "请求超时");
            }
            if (StringUtils.isEmpty(virtualSwitch.getName())) {
                return new BocloudResult(false, "参数name不能为空");
            }
            HmcVirtualSwitch oldVirtualSwitch = hmcVirtualSwitchRepository.getById(virtualSwitchId);
            if (null == oldVirtualSwitch) {
                logger.warn("Partition profile data not exist, {}", virtualSwitchId);
                return new BocloudResult(false, "ID为[" + virtualSwitchId + "]的虚拟交换机不存在");
            }
            if (!oldVirtualSwitch.getName().equals(virtualSwitch.getName())) {
                HmcVirtualSwitch virtualSwitchByName = hmcVirtualSwitchRepository.getByName(virtualSwitch.getName(),
                        oldVirtualSwitch.getServerId());
                if (virtualSwitchByName != null) {
                    return new BocloudResult(false, "名称为[" + virtualSwitch.getName() + "]的虚拟交换机已存在");
                }
            }
            HmcServer server = hmcServerRepository.getServerById(oldVirtualSwitch.getServerId());
            if (null == server) {
                logger.error("HMC server {} does not exist!", oldVirtualSwitch.getServerId());
                return new BocloudResult(false, "ID为[" + oldVirtualSwitch.getServerId() + "]的HMC服务器不存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
            if (null == vendor) {
                logger.error("vendor {} does not exist!", server.getVendorId());
                return new BocloudResult(false, "ID为[" + server.getVendorId() + "]的云平台不存在");
            }

            // 启动一个线程从MQ上获取数据
            taskExecutor.submit(() -> {

                String operate = vendor.getType().toLowerCase() + ".vswitch";
                String content = "HMC虚拟交换机[" + oldVirtualSwitch.getName() + "]修改失败";
                try {
                    ResourceEvent event = null;
                    HmcVirtualSwitchModel virtualSwitchModel = JSON.parseObject(JSON.toJSONString(virtualSwitch), HmcVirtualSwitchModel.class);
                    BocloudResult result = hmcVirtualNetworkDriver.updateVirtualSwitch(vendor.getUuid(),
                        virtualSwitchModel, server.getUuid(), oldVirtualSwitch.getUuid());
                    if (result.isSuccess()) {
                        VirtualSwitchEntry entry = (VirtualSwitchEntry) result.getData();
                        hmcDatabaseHelper.updateVirtualSwitch(oldVirtualSwitch, entry, context.getTarget());
                        event = new ResourceEvent(virtualSwitch.getId(), ServerAction.UPDATE.name(), "成功",
                                context.getTarget(), new Date(), "HMC", vendor.getId(), context.getCatalog());
                        content = "HMC虚拟交换机[" + oldVirtualSwitch.getName() + "]编辑成功";
                    } else {
                        event = new ResourceEvent(oldVirtualSwitch.getId(), ServerAction.UPDATE.name(), "失败",
                                context.getTarget(), new Date(), "HMC", vendor.getId(), context.getCatalog());
                        content = "HMC虚拟交换机[" + oldVirtualSwitch.getName() + "]编辑失败";
                    }
                    resourceEventRepository.save(event);
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), operateCategory, context));
                } catch (Exception e) {
                    logger.error("修改HMC虚拟交换机失败", e);
                    resourceEventPublisher.send(new OperateResult(false, content, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), operateCategory, context));
                }
            });
            return new BocloudResult(true, "修改任务已下发，正在执行...");
        } catch (Exception e) {
            logger.error("modify HMC partition profile failure:", e);
            return new BocloudResult(false, "修改虚拟交换机失败");
        }
    }

    @Override
    public BocloudResult<HmcVirtualSwitch> detail(Long id, Long serverId) {
        try {
            // 基本信息(常规)
            HmcVirtualSwitch virtualSwitch = this.hmcVirtualSwitchRepository.getById(id);
            if (virtualSwitch == null) {
                logger.warn("HMC virtual switch does not exist!");
                return new BocloudResult(false, null, "虚拟交换机不存在");
            }

            // 获取vlan列表
            List<Map<String, Object>> list = hmcProfileNetworkAdapterRepository
                    .getVlansBySwitchId(virtualSwitch.getSwitchId(), serverId);
            if (list != null && !list.isEmpty()) {
                Set<Integer> vlans = new HashSet<>();
                Map<String, Set<Integer>> partitions = new HashMap<>();
                for (Map<String, Object> item : list) {
                    Integer vlanId = Integer.parseInt(item.get("virtual_vlan_id").toString());
                    vlans.add(vlanId);
                    String partition = item.get("name").toString();
                    if (partitions.containsKey(partition)) {
                        partitions.get(partition).add(vlanId);
                    } else {
                        partitions.put(partition, new HashSet<>(0));
                        partitions.get(partition).add(vlanId);
                    }
                }

                virtualSwitch.setVlans(vlans);
                virtualSwitch.setPartition(partitions);
            }

            return new BocloudResult(true, virtualSwitch, "查询成功");
        } catch (Exception e) {
            logger.error("Query HMC virtual switch detail fail:", e);
            return new BocloudResult(false, "查询失败", null, null);
        }
    }

    @Override
    public BocloudResult<List<Integer>> getVlanIds(Long id) {
        try {
            HmcVirtualSwitch virtualSwitch = this.hmcVirtualSwitchRepository.getById(id);
            if (virtualSwitch == null) {
                return new BocloudResult(false, "未找到id为" + id + "的虚拟交换机");
            }

            Set<Integer> vlanIds = new HashSet<>();
            List<HmcPartition> hmcPartitions = this.hmcPartitionRepository.listByServerId(virtualSwitch.getServerId());
            for (HmcPartition hmcPartition : hmcPartitions) {
                if (HmcPartitionType.VIOS.getType().equals(hmcPartition.getPartitionType())) {
                    List<HmcPartitionNetworkAdapter> networkAdapters = this.hmcPartitionNetworkAdapterRepository
                            .getByPartitionIdAndSwitchId(hmcPartition.getId(), virtualSwitch.getSwitchId());
                    for (HmcPartitionNetworkAdapter networkAdapter : networkAdapters) {
                        vlanIds.add(networkAdapter.getVirtualVlanId());
                        if (networkAdapter.getTaggedVlanIds() != null) {
                            for (String s : networkAdapter.getTaggedVlanIds().split(" ")) {
                                vlanIds.add(Integer.parseInt(s));
                            }
                        }
                    }
                }
            }
            List<Integer> vlanIdList = new ArrayList<>(vlanIds);
            vlanIdList.sort(Integer::compareTo);
            return new BocloudResult(true, vlanIdList, "查询成功");
        } catch (Exception e) {
            logger.error("Query HMC virtual switch vlanIds fail:", e);
            return new BocloudResult(false, "查询失败", null, null);
        }
    }
}
