package com.bocloud.ims.service.resource;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

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 org.springframework.util.Assert;

import com.bocloud.cmp.driver.storage.SwitchDriver;
import com.bocloud.cmp.model.SwitcherModel;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.OperateResult;
import com.bocloud.common.model.Pager;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.NetworkCard;
import com.bocloud.ims.entity.resource.Server;
import com.bocloud.ims.entity.resource.Switcher;
import com.bocloud.ims.entity.resource.VendorTaskMsg;
import com.bocloud.ims.interfaces.resource.SwitcherService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.NetworkCardRepository;
import com.bocloud.ims.repository.resource.NetworkRepository;
import com.bocloud.ims.repository.resource.ServerRepository;
import com.bocloud.ims.repository.resource.SwitcherRepository;
import com.bocloud.ims.service.transporter.vendor.SmartxTransporter;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;

@Service
public class SwitchServiceImpl implements SwitcherService {

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

    @Autowired
    private ServerRepository serverRepository;
    @Autowired
    private SwitcherRepository switcherRepository;
    @Autowired
    private NetworkCardRepository networkCardRepository;
    @Autowired
    private NetworkRepository networkRepository;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private SwitchDriver switchDriver;
    @Autowired
    private SmartxTransporter smartTransporter;

    @Override
    public BocloudResult<GridBean<Switcher>> list(Pager pager, RequestContext requestContext) {
        int count = switcherRepository.count(pager.getParams());
        List<Switcher> list = switcherRepository.list(pager.getPage(), pager.getRows(), pager.getParams(), pager.getSorter());
        for (Switcher item : list) {
            List<NetworkCard> networkCards = networkCardRepository.listBySwitcher(item.getId(), "PM");
            item.setNetworkCards(networkCards);

            Map<String, List<NetworkCard>> hostNetworkCards = networkCards.stream().collect(Collectors.groupingBy(NetworkCard::getHostName));
            Map<String, List<String>> hostNetCards = new HashMap<>();
            for (Map.Entry<String, List<NetworkCard>> entry : hostNetworkCards.entrySet()) {
                hostNetCards.put(entry.getKey(), entry.getValue().stream().map(NetworkCard::getName).collect(Collectors.toList()));
            }
            item.setHostNetworkCards(hostNetCards);
        }
        GridBean<Switcher> gridBean = new GridBean<>(pager.getPage(), pager.getRows(), count, list);
        return new BocloudResult<>(true, gridBean, "success");
    }

    @Override
    public BocloudResult<Void> create(Switcher switcher, RequestContext requestContext) {
        SwitcherModel switcherModel = new SwitcherModel();

        Assert.notNull(switcher.getVendorId(), "需要参数vendorId");
        CloudVendor cloudVendor = cloudVendorRepository.query(switcher.getVendorId());
        Assert.notNull(cloudVendor, "未找到id为" + switcher.getVendorId() + "的云平台");

        Assert.notNull(switcher.getName(), "需要为虚拟交换机指定名称");
        boolean nameExists = switcherRepository.exists(switcher.getName(), cloudVendor.getId(), null);
        Assert.isTrue(!nameExists, "名为" + switcher.getName() +"的虚拟交换机已经存在，请重新命名");
        switcherModel.setName(switcher.getName());

        Assert.notNull(switcher.getBondMode(), "需要为虚拟交换机指定网口绑定模式");
        switcherModel.setBondMode(switcher.getBondMode());

        Map<String, List<String>> hostNetworkCards = new HashMap<>();
        Assert.notEmpty(switcher.getNetworkCards(), "需要为虚拟交换机指定要关联的物理网口");
        for (NetworkCard card : switcher.getNetworkCards()) {
            NetworkCard networkCard = networkCardRepository.query(card.getId());
            Assert.notNull(networkCard, "未找到id为" + card.getId() + "的物理网口");

            Server host = serverRepository.query(networkCard.getHostId());
            Assert.notNull(host, "未找到id为" + networkCard.getHostId() + "的主机");

            if (!hostNetworkCards.containsKey(host.getUuid())) {
                hostNetworkCards.put(host.getUuid(), new ArrayList<>());
            }
            hostNetworkCards.get(host.getUuid()).add(networkCard.getName());
        }
        switcherModel.setHostNetworkCards(hostNetworkCards);

        taskExecutor.execute(() -> {
            String path = cloudVendor.getType().toLowerCase() + "." + cloudVendor.getId() +".switcher";
            OperateResult operateResult = new OperateResult(true, "", "smart.switcher",
                    MapTools.simpleMap("vendorId", cloudVendor.getId()),
                    OperateResult.OperateCategory.ResourceEvent, requestContext);
            try (BocloudACLock lock = lockFactory.getACLock(path)){
                Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "当前存在其他互斥任务，请稍后再试");

                BocloudResult bocloudResult = switchDriver.create(cloudVendor.getUuid(), switcherModel);
                Assert.isTrue(bocloudResult.isSuccess(), bocloudResult.getMessage());

                String taskUuid = bocloudResult.getData().toString();
                VendorTaskMsg taskMsg = smartTransporter.getTask(cloudVendor, taskUuid, requestContext.getTarget());
                Assert.isTrue(taskMsg.getSmartSucceed(), taskMsg.getSmartFinalErrorMessage());

                bocloudResult = switchDriver.detail(cloudVendor.getUuid(), taskMsg.getTargetUuid());
                Assert.isTrue(bocloudResult.isSuccess(), bocloudResult.getMessage());

                SwitcherModel resultModel = (SwitcherModel) bocloudResult.getData();
                Switcher resultEntity = new Switcher();
                smartTransporter.convert(resultModel, resultEntity);
                resultEntity.setVendorId(cloudVendor.getId());
                resultEntity.setCreatorId(requestContext.getTarget());
                resultEntity.setGmtCreate(new Date());
                switcherRepository.save(resultEntity);

                smartTransporter.syncSwitcherUsedNetworkCard(resultEntity, resultModel.getHostNetworkCards());

                operateResult.setSuccess(false);
                operateResult.setMessage("创建虚拟交换机[" + switcher.getName() + "]成功");
                resourceEventPublisher.send(operateResult);
            } catch (Exception e) {
                logger.error("创建虚拟交换机[" + switcher.getName() + "]失败：", e);
                operateResult.setSuccess(false);
                operateResult.setMessage("创建虚拟交换机[" + switcher.getName() + "]失败：" + e.getMessage());
                resourceEventPublisher.send(operateResult);
            }
        });
        return new BocloudResult<>(true, "任务已经下发，正在执行...");
    }

    @Override
    public BocloudResult<Void> modify(Switcher switcher, RequestContext requestContext) {
        SwitcherModel switcherModel = new SwitcherModel();

        Assert.notNull(switcher.getId(), "需要参数id");
        Switcher dbSwitch = switcherRepository.query(switcher.getId());
        Assert.notNull(dbSwitch, "未找到id为" + switcher.getId() + "的虚拟交换机");

        switcher.setVendorId(dbSwitch.getVendorId());
        CloudVendor cloudVendor = cloudVendorRepository.query(switcher.getVendorId());
        Assert.notNull(cloudVendor, "未找到id为" + switcher.getVendorId() + "的云平台");

        Assert.notNull(switcher.getName(), "需要为虚拟交换机指定名称");
        switcherModel.setName(switcher.getName());

        Assert.notNull(switcher.getBondMode(), "需要为虚拟交换机指定网口绑定模式");
        switcherModel.setBondMode(switcher.getBondMode());

        Map<String, List<String>> hostNetworkCards = new HashMap<>();
        Assert.notEmpty(switcher.getNetworkCards(), "需要为虚拟交换机指定要关联的物理网口");
        for (NetworkCard card : switcher.getNetworkCards()) {
            NetworkCard networkCard = networkCardRepository.query(card.getId());
            Assert.notNull(networkCard, "未找到id为" + card.getId() + "的物理网口");

            Server host = serverRepository.query(networkCard.getHostId());
            Assert.notNull(host, "未找到id为" + networkCard.getHostId() + "的主机");

            if (!hostNetworkCards.containsKey(host.getUuid())) {
                hostNetworkCards.put(host.getUuid(), new ArrayList<>());
            }
            hostNetworkCards.get(host.getUuid()).add(networkCard.getName());
        }
        switcherModel.setHostNetworkCards(hostNetworkCards);

        taskExecutor.execute(() -> {
            String path = Switcher.class.getSimpleName() + "." + switcher.getId();
            OperateResult operateResult = new OperateResult(true, "", "smart.switcher",
                    MapTools.simpleMap("vendorId", cloudVendor.getId()),
                    OperateResult.OperateCategory.ResourceEvent, requestContext);
            try (BocloudACLock lock = lockFactory.getACLock(path)){
                Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "当前存在其他互斥任务，请稍后再试");

                BocloudResult bocloudResult = switchDriver.modify(cloudVendor.getUuid(), switcherModel);
                Assert.isTrue(bocloudResult.isSuccess(), bocloudResult.getMessage());

                String taskUuid = bocloudResult.getData().toString();
                VendorTaskMsg taskMsg = smartTransporter.getTask(cloudVendor, taskUuid, requestContext.getTarget());
                Assert.isTrue(taskMsg.getSmartSucceed(), taskMsg.getSmartFinalErrorMessage());

                bocloudResult = switchDriver.detail(cloudVendor.getUuid(), taskMsg.getTargetUuid());
                Assert.isTrue(bocloudResult.isSuccess(), bocloudResult.getMessage());

                SwitcherModel resultModel = (SwitcherModel) bocloudResult.getData();
                smartTransporter.convert(resultModel, dbSwitch);
                dbSwitch.setMenderId(requestContext.getTarget());
                dbSwitch.setGmtModify(new Date());
                switcherRepository.save(dbSwitch);

                smartTransporter.syncSwitcherUsedNetworkCard(dbSwitch, resultModel.getHostNetworkCards());

                operateResult.setSuccess(false);
                operateResult.setMessage("修改虚拟交换机[" + switcher.getName() + "]成功");
                resourceEventPublisher.send(operateResult);
            } catch (Exception e) {
                logger.error("修改虚拟交换机[" + switcher.getName() + "]失败：", e);
                operateResult.setSuccess(false);
                operateResult.setMessage("修改虚拟交换机[" + switcher.getName() + "]失败：" + e.getMessage());
                resourceEventPublisher.send(operateResult);
            }
        });
        return new BocloudResult<>(true, "任务已经下发，正在执行...");
    }

    @Override
    public BocloudResult<Void> remove(Long id, RequestContext requestContext) {

        Assert.notNull(id, "需要参数id");
        Switcher dbSwitch = switcherRepository.query(id);
        Assert.notNull(dbSwitch, "未找到id为" + id + "的虚拟交换机");

        CloudVendor cloudVendor = cloudVendorRepository.query(dbSwitch.getVendorId());
        Assert.notNull(cloudVendor, "未找到id为" + dbSwitch.getVendorId() + "的云平台");

        taskExecutor.execute(() -> {
            String path = Switcher.class.getSimpleName() + "." + id;
            OperateResult operateResult = new OperateResult(true, "", "smart.switcher",
                    MapTools.simpleMap("vendorId", cloudVendor.getId()),
                    OperateResult.OperateCategory.ResourceEvent, requestContext);
            try (BocloudACLock lock = lockFactory.getACLock(path)){
                Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "当前存在其他互斥任务，请稍后再试");

                SwitcherModel switcherModel = new SwitcherModel();
                switcherModel.setUuid(dbSwitch.getUuid());
                BocloudResult bocloudResult = switchDriver.remove(cloudVendor.getUuid(), switcherModel);
                Assert.isTrue(bocloudResult.isSuccess(), bocloudResult.getMessage());

                String taskUuid = bocloudResult.getData().toString();
                VendorTaskMsg taskMsg = smartTransporter.getTask(cloudVendor, taskUuid, requestContext.getTarget());
                Assert.isTrue(taskMsg.getSmartSucceed(), taskMsg.getSmartFinalErrorMessage());

                switcherRepository.remove(id, requestContext.getTarget());
                List<NetworkCard> networkCards = networkCardRepository.listBySwitcher(id, "PM");
                for (NetworkCard networkCard : networkCards) {
                    networkCard.setSwitcherId(null);
                    networkCardRepository.update(networkCard);
                }
                networkRepository.removeBySwitchId(id, requestContext.getTarget());

                operateResult.setSuccess(false);
                operateResult.setMessage("删除虚拟交换机[" + dbSwitch.getName() + "]成功");
                resourceEventPublisher.send(operateResult);
            } catch (Exception e) {
                logger.error("删除虚拟交换机[" + dbSwitch.getName() + "]失败：", e);
                operateResult.setSuccess(false);
                operateResult.setMessage("删除虚拟交换机[" + dbSwitch.getName() + "]失败：" + e.getMessage());
                resourceEventPublisher.send(operateResult);
            }
        });
        return new BocloudResult<>(true, "任务已经下发，正在执行...");
    }
}
