package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.compute.ServerDriver;
import com.bocloud.cmp.driver.network.NetworkCardDriver;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.model.NetBean;
import com.bocloud.cmp.model.NetworkCardModel;
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.*;
import com.bocloud.ims.interfaces.resource.NetworkCardService;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.service.task.ResourceTaskNotice;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Lists;
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 org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author ymh
 * @时间 2019年1月17日
 */
@Service("networkCardService")
public class NetworkCardServiceImpl implements NetworkCardService {

    private static Logger logger = LoggerFactory.getLogger(NetworkCardServiceImpl.class);
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private NetworkCardRepository networkCardRepository;
    @Autowired
    private NetworkCardDriver networkCardDriver;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private VpcRepository vpcRepository;
    @Autowired
    private SubnetRepository subnetRepository;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private FloatingIpRepository floatingIpRepository;
    @Autowired
    private SecurityGroupRepository securityGroupRepository;
    @Autowired
    private ServerDriver serverDriver;
    @Autowired
    private ResourceTaskNotice resourceTaskNotice;

    @Override
    public BocloudResult<GridBean<NetworkCard>> list(Pager pager) {
        GridBean gridBean = null;
        int total = 0;
        List<NetworkCard> list = Lists.newArrayList();
        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) {
                params = new ArrayList<>();
            }
            if (null == sorter) {
                sorter = Maps.newHashMap();
            }
            sorter.put("gmtCreate", Common.ONE);
            total = networkCardRepository.count(params);
            if (simple) {
                List<SimpleBean> beans = networkCardRepository.list(params, sorter);
                gridBean = new GridBean(1, 1, total, beans);
            } else {
                list = networkCardRepository.list(page, rows, params, sorter);
                gridBean = GridHelper.getBean(page, rows, total, list);
            }
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("list network failure:", e);
            return new BocloudResult<>(false, "查询失败", null, null);
        }
    }

    @Override
    public BocloudResult unBandList(Long vendorId) {
        List<NetworkCard> list = Lists.newArrayList();
        try {
            NetworkCard networkCard = null;
            List<CloudServer> cloudServers = cloudServerRepository.listByVendorId(vendorId);
            for (CloudServer cloudServer : cloudServers) {
                List<String> privateIps = JSONArray.parseArray(cloudServer.getPrivateIps(), String.class);
                List<String> publicIps = JSONArray.parseArray(cloudServer.getPublicIps(), String.class);
                if (publicIps == null || (privateIps.size() != publicIps.size() && privateIps.size() == 1)) {
                    networkCard = new NetworkCard();
                    networkCard.setIpAddress(privateIps.get(0));
                    networkCard.setInstanceId(cloudServer.getInstanceId());
                    networkCard.setServerName(cloudServer.getName());
                    networkCard.setRegionId(cloudServer.getRegionId());
                    networkCard.setRegionName(cloudServer.getRegionName());
                    list.add(networkCard);
                } else if (privateIps.size() != publicIps.size()) {
                    for (String privateIp : privateIps) {
                        FloatingIp floatingIp = floatingIpRepository.getByFixedIpAddress(privateIp, vendorId);
                        if (floatingIp == null) {
                            networkCard = new NetworkCard();
                            networkCard.setIpAddress(privateIp);
                            networkCard.setInstanceId(cloudServer.getInstanceId());
                            networkCard.setServerName(cloudServer.getName());
                            networkCard.setRegionId(cloudServer.getRegionId());
                            networkCard.setRegionName(cloudServer.getRegionName());
                            list.add(networkCard);
                        }
                    }
                }
            }

            return new BocloudResult(true, list, "查询成功");
        } catch (Exception e) {
            logger.error("list network failure:", e);
            return new BocloudResult(false, "查询失败", null, null);
        }
    }

    @Override
    public BocloudResult create(NetworkCard networkCard, RequestContext context) {
        try {
            if (null == networkCard) {
                return new BocloudResult<>(false, "参数格式有误");
            }
            Long vendorId = networkCard.getVendorId();
            CloudVendor cloudVendor = cloudVendorRepository.query(vendorId);
            if (null == cloudVendor) {
                return new BocloudResult<>(false, "平台信息不存在");
            }
            Long vpcId = networkCard.getVpcId();
            Vpc vpc = vpcRepository.query(vpcId);
            if (null == vpc) {
                return new BocloudResult<>(false, "虚拟VPC不存在");
            }
            Long subnetId = networkCard.getSubnetId();
            Subnet subnet = subnetRepository.query(subnetId);
            if (null == subnet) {
                return new BocloudResult<>(false, "子网不存在");
            }
            if (!ListTool.isEmpty(networkCard.getSecurityGroupIds())) {
                for (String sgUuid : networkCard.getSecurityGroupIds()) {
                    SecurityGroup byGroupId = securityGroupRepository.getByGroupId(sgUuid);
                    if (null == byGroupId) {
                        return new BocloudResult<>(false, "安全组不存在");
                    }
                }
            }
            new Thread(new Runnable() {
                @Override
                public void run() {
                    String content = "网卡创建失败";
                    String operate = cloudVendor.getType().toLowerCase() + ".networkcard";
                    Boolean resultFlag = false;
                    try {
                        NetworkCardModel networkCardModel = JSON.parseObject(JSON.toJSONString(networkCard),
                                NetworkCardModel.class);
                        networkCardModel.setVpcUuid(vpc.getVpcId());
                        networkCardModel.setSubnetUuid(subnet.getSubnetUuid());
                        BocloudResult bocloudResult = networkCardDriver.create(cloudVendor.getUuid(), networkCardModel,
                                networkCard.getRegionId());
                        if (bocloudResult.isSuccess()) {
                            NetworkCard networkCard = JSON.parseObject(JSON.toJSONString(bocloudResult.getData()),
                                    NetworkCard.class);
                            networkCard.setMenderId(context.getTarget());
                            networkCard.setRegionId(networkCardModel.getRegionId());
                            networkCard.setGmtModify(new Date());
                            networkCard.setCreatorId(context.getTarget());
                            networkCard.setVendorId(vendorId);
                            networkCardRepository.save(networkCard);
                            content = "网卡创建成功";
                            resultFlag = true;
                        } else {
                            content = bocloudResult.getMessage();
                        }
                    } catch (Exception e) {
                        logger.error("网卡创建失败 ： " + e);
                        content = e.getMessage();
                    }
                    resourceEventPublisher.send(new OperateResult(resultFlag, content, operate,
                            MapTools.simpleMap(Common.VENDORID, vendorId), OperateResult.OperateCategory.ResourceEvent,
                            context));
                }
            }).start();
            return new BocloudResult<>(true, "申请网卡任务已下发...");
        } catch (Exception e) {
            logger.error("create network fail:", e);
            return new BocloudResult<>(false, "创建失败");
        }
    }

    @Override
    public BocloudResult remove(Long id, RequestContext context) {
        String path = Network.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            NetworkCard networkCard = networkCardRepository.query(id);
            if (null == networkCard) {
                logger.warn("network cart 不存在!");
                return new BocloudResult<>(false, "网卡不存在");
            }
            Boolean isPrimary = networkCard.getIsPrimary();
            if (isPrimary) {
                return new BocloudResult<>(false, "主网卡不允许卸载");
            }
            Long vendorId = networkCard.getVendorId();
            CloudVendor cloudVendor = cloudVendorRepository.query(vendorId);
            if (null == cloudVendor) {
                return new BocloudResult<>(false, "平台信息不存在");
            }
            BocloudResult bocloudResult = networkCardDriver.remove(cloudVendor.getUuid(),
                    networkCard.getNetworkcardUuid(), networkCard.getRegionId());
            if (bocloudResult.isSuccess()) {
                // 更新浮动IP状态
                FloatingIp floatingIp = floatingIpRepository.getByNetworkCardUuid(networkCard.getNetworkcardUuid(),
                        cloudVendor.getId());
                if (null != floatingIp) {
                    floatingIp.setStatus("UNBIND");
                    floatingIp.setInstanceId(null);
                    floatingIp.setNetworkCardUuid(null);
                    floatingIp.setGmtModify(new Date());
                    floatingIp.setMenderId(context.getTarget());
                    floatingIpRepository.update(floatingIp);
                }
                networkCardRepository.remove(networkCard.getId(), context.getTarget());
                return new BocloudResult<>(true, "删除成功");
            } else {
                return new BocloudResult<>(false, bocloudResult.getMessage());
            }
        } catch (Exception e) {
            logger.error("remove network fail:", e);
            return new BocloudResult<>(false, "删除失败");
        }
    }

    @Override
    public BocloudResult<NetworkCard> detail(Long id) {
        try {
            NetworkCard networkCard = networkCardRepository.query(id);
            if (null == networkCard) {
                return new BocloudResult<>(false, "网卡数据不存在");
            }
            return new BocloudResult<>(true, networkCard, "查询成功");
        } catch (Exception e) {
            logger.error("create network fail:", e);
            return new BocloudResult<>(false, "创建失败");
        }
    }

    @Override
    public BocloudResult modify(NetBean bean, RequestContext context) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    @Transactional
    public BocloudResult attachNetworkCard(NetworkCard networkCardParam, RequestContext context) {
        Long id = networkCardParam.getId();
        String path = NetworkCard.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            NetworkCard networkCard = networkCardRepository.query(id);
            if (null == networkCard) {
                logger.warn("network cart 不存在!");
                return new BocloudResult<>(false, "网卡不存在");
            }
            CloudVendor cloudVendor = cloudVendorRepository.query(networkCard.getVendorId());
            if (null == cloudVendor) {
                return new BocloudResult<>(false, "平台不存在");
            }
            Long serverId = networkCardParam.getServerId();
            CloudServer cloudServer = cloudServerRepository.query(serverId);
            if (null == cloudServer) {
                return new BocloudResult<>(false, "云主机不存在");
            }
            List<NetworkCard> netList = networkCardRepository.listByInstanceId(cloudServer.getInstanceId(),
                    cloudVendor.getId());
            if (null != netList && netList.size() >= 2) {
                return new BocloudResult<>(false, "该云主机没有可用的网卡配额");
            }
            if (CloudProvider.VOLCENGINE.name().equalsIgnoreCase(cloudVendor.getType())) {
                if (!StringUtils.isEmpty(networkCard.getInstanceId())) {
                    return new BocloudResult<>(false, "网卡已绑定的内网IP超过该云主机的网卡内网IP配额");
                }
            } else {
                List<JSONObject> ipArray = JSON.parseArray(networkCard.getIpAddress(), JSONObject.class);
                if (null != ipArray && ipArray.size() > 1) {
                    return new BocloudResult<>(false, "网卡已绑定的内网IP超过该云主机的网卡内网IP配额");
                }
            }
            new Thread(new Runnable() {
                @Override
                public void run() {
                    String content = "绑定失败";
                    String operate = cloudVendor.getType().toLowerCase() + ".networkcard";
                    Boolean resultFlag = false;
                    try {
                        NetworkCardModel networkCardModel = new NetworkCardModel();
                        networkCardModel.setNetworkcardUuid(networkCard.getNetworkcardUuid());
                        networkCardModel.setInstanceId(cloudServer.getInstanceId());
                        BocloudResult bocloudResult = networkCardDriver.attachNetworkCard(cloudVendor.getUuid(),
                                networkCardModel, networkCard.getRegionId());
                        if (bocloudResult.isSuccess()) {
                            content = "绑定成功";
                            resultFlag = true;
                            NetworkCard newNetworkCard = JSON.parseObject(JSON.toJSONString(bocloudResult.getData()),
                                    NetworkCard.class);
                            if (null != newNetworkCard.getLabel()) {
                                networkCard.setLabel(newNetworkCard.getLabel());
                            }
                            networkCard.setInstanceId(cloudServer.getInstanceId());
                            networkCard.setUsed(newNetworkCard.getUsed());
                            networkCard.setMenderId(context.getTarget());
                            networkCard.setGmtModify(new Date());
                            networkCard.setCategory("VM");
                            networkCardRepository.update(networkCard);
                            if (CloudProvider.VOLCENGINE.name().equalsIgnoreCase(cloudVendor.getType())) {
                                BocloudResult detail = serverDriver.detail(cloudServer.getInstanceId(), cloudVendor.getUuid(), networkCard.getRegionId());
                                CloudServer cloudServerUpdate = JSONObject.parseObject(JSONObject.toJSONString(detail.getData()), CloudServer.class);
                                if (null != cloudServer) {
                                    cloudServer.setPrivateIps(cloudServerUpdate.getPrivateIps());
                                    cloudServerRepository.update(cloudServer);
                                    //发送消息给cop
                                    resourceTaskNotice.sendLogicalMessage(cloudServer, ResourceTaskNotice.Action.UPDATE);
                                }
                            }
                        } else {
                            content = bocloudResult.getMessage();
                        }
                    } catch (Exception e) {
                        logger.error("网卡绑定失败 ： " + e);
                        content = e.getMessage();
                    }
                    resourceEventPublisher.send(new OperateResult(resultFlag, content, operate,
                            MapTools.simpleMap(Common.VENDORID, cloudVendor.getId()),
                            OperateResult.OperateCategory.ResourceEvent, context));
                }
            }).start();
            return new BocloudResult<>(true, "绑定任务已下发...");
        } catch (Exception e) {
            logger.error("remove network fail:", e);
            return new BocloudResult<>(false, "绑定失败");
        }
    }

    @Override
    public BocloudResult detachNetworkCard(Long id, RequestContext context) {
        String path = NetworkCard.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            NetworkCard networkCard = networkCardRepository.query(id);
            Assert.notNull(networkCard, "参数格式错误");
            CloudVendor cloudVendor = cloudVendorRepository.query(networkCard.getVendorId());
            if (null == cloudVendor) {
                return new BocloudResult<>(false, "平台不存在");
            }
            CloudServer cloudServer = cloudServerRepository.getByInstanceId(networkCard.getInstanceId());
            if (null == cloudServer) {
                return new BocloudResult<>(false, "云主机不存在");
            }
            new Thread(new Runnable() {
                @Override
                public void run() {
                    String content = "解绑失败";
                    String operate = cloudVendor.getType().toLowerCase() + ".networkcard";
                    Boolean resultFlag = false;
                    try {
                        NetworkCardModel networkCardModel = new NetworkCardModel();
                        networkCardModel.setNetworkcardUuid(networkCard.getNetworkcardUuid());
                        networkCardModel.setInstanceId(networkCard.getInstanceId());
                        BocloudResult bocloudResult = networkCardDriver.detachNetworkCard(cloudVendor.getUuid(),
                                networkCardModel, networkCard.getRegionId());
                        if (bocloudResult.isSuccess()) {
                            if (CloudProvider.VOLCENGINE.name().equalsIgnoreCase(cloudVendor.getType())) {
                                BocloudResult detail = serverDriver.detail(networkCard.getInstanceId(), cloudVendor.getUuid(), networkCard.getRegionId());
                                CloudServer cloudServerUpdate = JSONObject.parseObject(JSONObject.toJSONString(detail.getData()), CloudServer.class);
                                if (null != cloudServer) {
                                    cloudServer.setPrivateIps(cloudServerUpdate.getPrivateIps());
                                    cloudServerRepository.update(cloudServer);
                                    //发送消息cop
                                    resourceTaskNotice.sendLogicalMessage(cloudServer, ResourceTaskNotice.Action.UPDATE);
                                }
                            }
                            content = "解绑成功";
                            resultFlag = true;
                            NetworkCard newNetworkCard = JSON.parseObject(JSON.toJSONString(bocloudResult.getData()),
                                    NetworkCard.class);
                            networkCard.setLabel(newNetworkCard.getLabel());
                            networkCard.setUsed(newNetworkCard.getUsed());
                            networkCard.setMenderId(context.getTarget());
                            networkCard.setGmtModify(new Date());
                            networkCard.setInstanceId(null);
                            networkCard.setCategory(null);
                            networkCardRepository.update(networkCard);
                        } else {
                            content = bocloudResult.getMessage();
                        }
                    } catch (Exception e) {
                        logger.error("网卡解绑失败 ： " + e);
                        content = e.getMessage();
                    }
                    resourceEventPublisher.send(new OperateResult(resultFlag, content, operate,
                            MapTools.simpleMap(Common.VENDORID, cloudVendor.getId()),
                            OperateResult.OperateCategory.ResourceEvent, context));
                }
            }).start();
            return new BocloudResult<>(true, "解绑任务已下发...");
        } catch (Exception e) {
            logger.error("remove network fail:", e);
            return new BocloudResult<>(false, "解绑失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult batchRemove(List<Long> idArray, RequestContext context) {
        try {
            // 获取资源ID
            if (ListTool.isEmpty(idArray)) {
                return new BocloudResult<>(false, "请选择需要删除的网卡数据！");
            }
            NetworkCard networkCard = networkCardRepository.query(idArray.get(0));
            if (null == networkCard) {
                return new BocloudResult<>(false, "数据异常！");
            }
            CloudVendor vendor = cloudVendorRepository.query(networkCard.getVendorId());
            if (null == vendor) {
                return new BocloudResult<>(false, "平台信息异常！");
            }
            new Thread(new Runnable() {
                @Override
                public void run() {
                    String operate = vendor.getType().toLowerCase() + ".networkcard";
                    try {
                        List<BocloudResult> succList = Lists.newArrayList();
                        List<BocloudResult> failList = Lists.newArrayList();
                        for (Long id : idArray) {
                            BocloudResult bocloudResult = remove(id, context);
                            if (bocloudResult.isSuccess()) {
                                succList.add(bocloudResult);
                            } else {
                                failList.add(bocloudResult);
                            }
                        }
                        // 删除成功的数量
                        int success = succList.size();
                        // 删除失败的数量
                        int fail = failList.size();
                        String content = null;
                        if (fail == idArray.size()) {
                            content = "网卡批量删除失败，详情如下：\n";
                            for (BocloudResult bocloudResult : failList) {
                                content += bocloudResult.getMessage() + "\n";
                            }
                        } else if (success == idArray.size()) {
                            content = "网卡批量删除成功【" + success + "】个";
                        } else {
                            content = "网卡批量删除成功【" + success + "】个,失败【" + fail + "】个，失败详情如下：\n";
                            for (BocloudResult bocloudResult : failList) {
                                content += bocloudResult.getMessage() + "\n";
                            }
                        }
                        resourceEventPublisher.send(new OperateResult(fail == idArray.size() ? false : true, content,
                                operate, MapTools.simpleMap(Common.VENDORID, vendor.getId()),
                                OperateResult.OperateCategory.ResourceEvent, context));
                    } catch (Exception e) {
                        logger.error("批量删除任务异常：" + e.getMessage());
                        resourceEventPublisher.send(new OperateResult(false, "批量删除任务异常：" + e.getMessage(), operate,
                                MapTools.simpleMap(Common.VENDORID, vendor.getId()),
                                OperateResult.OperateCategory.ResourceEvent, context));
                    }
                }
            }).start();
            return new BocloudResult<>(true, "删除任务已下发，正在执行...");
        } catch (Exception e) {
            logger.error("delete error ：", e);
            return new BocloudResult<>(false, "批量删除失败！");
        }
    }

}
