package com.bocloud.ims.service.resource;

import com.bocloud.common.model.*;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.entity.resource.Cluster;
import com.bocloud.ims.entity.resource.SchedulerPolicy;
import com.bocloud.ims.interfaces.resource.SchedulerPolicyService;
import com.bocloud.ims.repository.resource.ClusterRepository;
import com.bocloud.ims.repository.resource.SchedulerPolicyRepository;
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.util.Assert;

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

/**
 * 资源调度service实现
 *
 * @author wangyu
 * @version 4.1.0-SNAPSHOT
 * @since 2018/12/24
 */
@Service("schedulerPolicyService")
public class SchedulerPolicyServiceImpl implements SchedulerPolicyService {

    private static final Logger logger = LoggerFactory.getLogger(SchedulerPolicyServiceImpl.class);
    @Autowired
    private SchedulerPolicyRepository schedulerPolicyRepository;
    @Autowired
    private ClusterRepository clusterRepository;
    @Autowired
    private LockFactory lockFactory;

    /**
     * 分页查询
     *
     * @param page
     * @param rows
     * @param params
     * @param sorter
     * @param simple
     * @return
     */
    @Override
    public BocloudResult<GridBean<SchedulerPolicy>> 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) {
                params = new ArrayList<>();
            }
            if (null == sorter) {
                sorter = Maps.newHashMap();
            }
            int total = this.schedulerPolicyRepository.count(params);
            if (simple) {
                List<SimpleBean> beans = this.schedulerPolicyRepository.list(params, sorter);
                gridBean = new GridBean(1, 1, total, beans);
            } else {
                List<SchedulerPolicy> policies = this.schedulerPolicyRepository.list(page, rows, params, sorter);
                gridBean = GridHelper.getBean(page, rows, total, policies);
            }
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("Query SchedulerPolicy list fail:", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    /**
     * 创建调度策略
     *
     * @param schedulerPolicy
     * @param context
     * @return
     */
    @Override
    public BocloudResult<SchedulerPolicy> create(SchedulerPolicy schedulerPolicy, RequestContext context) {
        try {
            if (schedulerPolicyRepository.existName(schedulerPolicy.getName())) {
                return new BocloudResult<SchedulerPolicy>(false, "名称已存在");
            }
            if (schedulerPolicyRepository.exist(schedulerPolicy.getPolicy(), schedulerPolicy.getPolicyCategory())) {
                return new BocloudResult<SchedulerPolicy>(false, "该类型策略已存在");
            }
            schedulerPolicy.setCreatorId(context.getTarget());
            schedulerPolicy.setMenderId(context.getTarget());
            this.schedulerPolicyRepository.save(schedulerPolicy);
            return new BocloudResult<SchedulerPolicy>(true, schedulerPolicy, "添加成功");
        } catch (Exception e) {
            logger.error("creat SchedulerPolicy error:", e);
            return new BocloudResult<SchedulerPolicy>(false, "添加失败");
        }
    }

    /**
     * 修改调度策略
     *
     * @param schedulerPolicy
     * @param user
     * @return
     */
    @Override
    public BocloudResult<SchedulerPolicy> modify(SchedulerPolicy schedulerPolicy, RequestContext context) {
        String path = SchedulerPolicy.class.getSimpleName() + "_" + schedulerPolicy.getId();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            SchedulerPolicy policy = this.schedulerPolicyRepository.query(schedulerPolicy.getId());
            if (null == policy) {
                logger.warn("SchedulerPolicy does not exist!");
                return new BocloudResult<SchedulerPolicy>(false, "数据不存在");
            }
            if (!policy.getName().equals(schedulerPolicy.getName())) {
                if (schedulerPolicyRepository.existName(schedulerPolicy.getName())) {
                    logger.warn("SchedulerPolicy already exist!");
                    return new BocloudResult<SchedulerPolicy>(false, "策略名称已存在");
                }
            }
            policy.setRemark(schedulerPolicy.getRemark());
            policy.setPolicy(schedulerPolicy.getPolicy());
            policy.setPolicyCategory(schedulerPolicy.getPolicyCategory());
            policy.setMenderId(context.getTarget());
            policy.setGmtModify(new Date());
            this.schedulerPolicyRepository.update(policy);
            return new BocloudResult<SchedulerPolicy>(true, policy, "修改成功");
        } catch (Exception e) {
            logger.error("Modify SchedulerPolicy fail:", e);
            return new BocloudResult<SchedulerPolicy>(false, "修改失败");
        }
    }

    @Override
    public BocloudResult<String> remove(Long id, RequestContext context) {
        String path = SchedulerPolicy.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            SchedulerPolicy policy = schedulerPolicyRepository.query(id);
            if (null == policy) {
                logger.warn("SchedulerPolicy data not exist");
                return new BocloudResult<>(false, "数据不存在");
            }
            boolean result = this.schedulerPolicyRepository.remove(id, context.getTarget());
            if (result) {
                // 重置集群
                clusterRepository.reset(id, context.getTarget());
                return new BocloudResult<>(true, "删除成功");
            } else {
                return new BocloudResult<>(false, "删除失败");
            }
        } catch (Exception e) {
            logger.error("remove SchedulerPolicy fail:", e);
            return new BocloudResult<>(false, "删除策略失败");
        }
    }

    /**
     * 查询详细
     *
     * @param id
     * @return
     */
    @Override
    public BocloudResult<SchedulerPolicy> detail(Long id) {
        try {
            SchedulerPolicy policy = this.schedulerPolicyRepository.query(id);
            if (null == policy) {
                logger.warn("SchedulerPolicy data not exist");
                return new BocloudResult<>(false, "数据不存在");
            }
            return new BocloudResult<>(true, policy, "查询详情成功");
        } catch (Exception e) {
            logger.error("query SchedulerPolicy detail fail:", e);
            return new BocloudResult<>(false, "查询详情失败");
        }
    }

    /**
     * @param id
     * @param clusterIds
     * @param user
     * @return
     */
    @Override
    public BocloudResult<SchedulerPolicy> clusterBind(Long id, List<Long> clusterIds, RequestContext context) {
        try {
            SchedulerPolicy policy = this.schedulerPolicyRepository.query(id);
            if (null == policy) {
                logger.warn("SchedulerPolicy data not exist");
                return new BocloudResult<>(false, "数据不存在");
            }
            List<Cluster> clusters = clusterRepository.listByPolicyId(policy.getId());
            for (Cluster cluster : clusters) {
                this.updateCluster(cluster.getId(), null, context.getTarget());
            }
            if (ListTool.isEmpty(clusterIds)) {
                return new BocloudResult<>(true, policy, "集群清空绑定成功");
            } else {
                for (Long clusterId : clusterIds) {
                    this.updateCluster(clusterId, policy.getId(), context.getTarget());
                }
                return new BocloudResult<>(true, policy, "集群绑定成功");
            }
        } catch (Exception e) {
            logger.error("query SchedulerPolicy detail fail:", e);
            return new BocloudResult<>(false, "集群绑定失败");
        }
    }

    /**
     * 更新集群
     *
     * @param clusterId
     * @param policyId
     * @param userId
     * @return
     */
    private BocloudResult<String> updateCluster(Long clusterId, Long policyId, Long userId) {
        String path = Cluster.class.getSimpleName() + "_" + clusterId;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Cluster cluster = this.clusterRepository.query(clusterId);
            if (null == cluster) {
                logger.warn("Cluster data not exist");
                return new BocloudResult<>(false, "集群不存在");
            }
            cluster.setPolicyId(policyId);
            cluster.setMenderId(userId);
            cluster.setGmtModify(new Date());
            clusterRepository.update(cluster);
            return new BocloudResult<>(true, "集群更新成功");
        } catch (Exception e) {
            logger.error("query SchedulerPolicy detail fail:", e);
            return new BocloudResult<>(false, "集群更新失败");
        }
    }
}
