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

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.storage.DataStoreDriver;
import com.bocloud.cmp.model.DataStoreModel;
import com.bocloud.common.model.*;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.DataStore;
import com.bocloud.ims.entity.resource.Server;
import com.bocloud.ims.entity.resource.Vdc;
import com.bocloud.ims.entity.resource.fusionsphere.FusionSphereStorageDevice;
import com.bocloud.ims.interfaces.resource.fusionsphere.FusionSphereDataStoreService;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.repository.resource.fusionsphere.FusionSphereStorageDeviceRepository;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

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

/**
 * @Company: 博云 www.bocloud.com
 * @ClassName: FusionSphereDataStoreServiceImpl
 * @Description:
 * @author: zhenpingLi/李振平
 * @date: 2021/10/20 17:55
 */
@Slf4j
@Service
public class FusionSphereDataStoreServiceImpl implements FusionSphereDataStoreService {

    private static OperateResult.OperateCategory operateCategory = OperateResult.OperateCategory.ResourceEvent;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private CloudVendorRepository vendorRepository;
    @Autowired
    private VdcRepository vdcRepository;
    @Autowired
    private DataStoreRepository dataStoreRepository;
    @Autowired
    private FusionSphereStorageDeviceRepository fusionSphereStorageDeviceRepository;
    @Autowired
    private ServerRepository serverRepository;
    @Autowired
    private DataStoreDriver dataStoreDriver;
    @Autowired
    private PoolGroupRelationRepository poolGroupRelationRepository;

    @Override
    public BocloudResult<GridBean<DataStore>> list(Pager pager, RequestContext context) {
        List<Param> params = Optional.ofNullable(pager.getParams()).orElse(new ArrayList<>());
        Map<String, String> sorter = Optional.ofNullable(pager.getSorter()).orElse(Maps.newHashMap());
        Integer page = Optional.ofNullable(pager.getPage()).orElse(1);
        Integer rows = Optional.ofNullable(pager.getRows()).orElse(10);
        try {
            int total = dataStoreRepository.count(params);
            List<DataStore> list = this.dataStoreRepository.list(page, rows, params, sorter);
            GridBean<DataStore> gridBean = new GridBean<>(page, rows, total, list);
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            log.error("list DataStore error!", e);
            return new BocloudResult<>(false, "查询失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<DataStore> detail(Long id, RequestContext context) {
        try {
            DataStore entity = dataStoreRepository.query(id);
            Assert.notNull(entity, "资源不存在");
            return new BocloudResult<>(true, entity, "查询详情成功");
        } catch (Exception e) {
            log.error("detail DataStore fail:", e);
            return new BocloudResult<>(false, "查询详情失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<Void> create(DataStore entityParams, RequestContext context) {
        try {
            CloudVendor vendor = vendorRepository.query(entityParams.getVendorId());
            Assert.notNull(vendor, "平台验证失败");
            Vdc vdc = vdcRepository.query(entityParams.getVdcId());
            Assert.notNull(vdc, "站点不存在");
            FusionSphereStorageDevice storageDevice = fusionSphereStorageDeviceRepository.query(entityParams.getStorageDeviceId());
            Assert.notNull(storageDevice, "存储设备不存在");
            if (null != dataStoreRepository.getByName(entityParams.getName(), entityParams.getVdcId())) {
                throw new RuntimeException("资源已存在");
            }
            Server server = serverRepository.query(entityParams.getServerId());

            DataStoreModel model = new DataStoreModel();
            model.setName(entityParams.getName());
            model.setStoreDeviceUuid(storageDevice.getUrn());
            model.setRemark(entityParams.getRemark());
            model.setUseType(entityParams.getUseType());
            Optional.ofNullable(server).map(host -> host.getUuid()).ifPresent(model::setHostUuid);

            model.setVdcUri(vdc.getUri());

            taskExecutor.execute(() -> {
                String operate = vendor.getType().toLowerCase() + ".datastore";
                String message = "创建资源失败";
                BocloudResult result = dataStoreDriver.create(vendor.getUuid(), model);
                try {
                    if (result.isSuccess()) {
                        message = "创建资源成功";
                        DataStoreModel newModel = JSONObject.parseObject(JSONObject.toJSONString(result.getData()), DataStoreModel.class);
                        entityParams.setStoreVal(newModel.getStoreVal());
                        entityParams.setUri(newModel.getUri());
                        entityParams.setStatus(newModel.getStatus());
                        entityParams.setType(newModel.getType());
                        entityParams.setFreeSpace(newModel.getFreeSpace().longValue());
                        entityParams.setCapacity(newModel.getCapacity().longValue());
                        dataStoreRepository.save(entityParams);
                    } else {
                        log.error("创建资源失败：" + result.getMessage());
                        message = result.getMessage();
                    }
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), message, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), operateCategory, context));
                } catch (Exception e) {
                    log.error("create resource fail:", e);
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), message, operate, MapTools.simpleMap(
                            "vendorId", vendor.getId()), operateCategory, context));
                }
            });
            return new BocloudResult<>(true, "任务已下发，正在执行...");
        } catch (Exception e) {
            log.error("create resource error!", e);
            return new BocloudResult<>(false, "创建失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<Void> modify(DataStore modifyParams, RequestContext context) {
        try {
            DataStore entity = dataStoreRepository.query(modifyParams.getId());
            Assert.notNull(entity, "数据不存在");
            CloudVendor vendor = vendorRepository.query(entity.getVendorId());
            Assert.notNull(vendor, "平台验证失败");

            DataStoreModel model = new DataStoreModel();
            model.setUri(entity.getUri());
            model.setName(modifyParams.getName());
            model.setRemark(modifyParams.getRemark());

            taskExecutor.execute(() -> {
                String operate = vendor.getType().toLowerCase() + ".datastore";
                String message = "更新datastore失败";
                BocloudResult result = dataStoreDriver.modify(vendor.getUuid(), model);
                try {
                    if (result.isSuccess()) {
                        entity.setName(modifyParams.getName());
                        entity.setRemark(modifyParams.getRemark());
                        dataStoreRepository.update(entity);
                        message = "更新datastore成功";
                    } else {
                        log.error("更新datastore失败：" + result.getMessage());
                        message = result.getMessage();
                    }
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), message, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), operateCategory, context));
                } catch (Exception e) {
                    log.error("modify datastore fail:", e);
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), message, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), operateCategory, context));
                }
            });
            return new BocloudResult<>(true, "任务已下发，正在执行...");
        } catch (Exception e) {
            log.error("modify datastore error!", e);
            return new BocloudResult<>(false, "更新失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<Void> remove(Long id, RequestContext context) {
        String path = DataStore.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            DataStore entity = dataStoreRepository.query(id);
            Assert.notNull(entity, "数据不存在");
            CloudVendor vendor = vendorRepository.query(entity.getVendorId());
            Assert.notNull(vendor, "平台验证失败");

            taskExecutor.execute(() -> {
                String operate = vendor.getType().toLowerCase() + ".datastore";
                String message = "删除datastore失败";
                BocloudResult result = dataStoreDriver.remove(vendor.getUuid(), entity.getUri());
                try {
                    if (result.isSuccess()) {
                        message = "删除datastore成功";
                        dataStoreRepository.remove(id, context.getTarget());
                        // 删除存储与cmp资源池的关系
                        poolGroupRelationRepository.removeByTarget(id, "Storage");
                    } else {
                        log.error("删除datastore失败：" + result.getMessage());
                        message = result.getMessage();
                    }
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), message, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), operateCategory, context));
                } catch (Exception e) {
                    log.error("remove datastore fail:", e);
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), message, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), operateCategory, context));
                }
            });
            return new BocloudResult<>(true, "任务已下发，正在执行...");
        } catch (Exception e) {
            log.error("remove datastore error!", e);
            return new BocloudResult<>(false, "删除失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult listFile(Long id, RequestContext context) {
        try {
            DataStore entity = dataStoreRepository.query(id);
            Assert.notNull(entity, "资源不存在");
            CloudVendor vendor = vendorRepository.query(entity.getVendorId());
            Assert.notNull(vendor, "平台验证失败");
            return dataStoreDriver.listFile(vendor.getUuid(), entity.getUri());
        } catch (Exception e) {
            log.error("listFile DataStore fail:", e);
            return new BocloudResult<>(false, "查询文件失败:" + e.getMessage());
        }
    }
}