package com.bocloud.ims.service.scheduler;

import com.bocloud.cmp.vm.model.VmSnapshotParam;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.SnapshotTask;
import com.bocloud.ims.interfaces.resource.CloudServerService;
import com.bocloud.ims.interfaces.scheduler.SnapshotTaskService;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.SnapshotTaskRepository;
import com.bocloud.ims.service.config.DefaultSchedulingConfigurer;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.config.TriggerTask;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 定时任务调整
 *
 * @author ymh
 * @date 2021/05/31
 */
@Service
public class SnapshotTaskServiceImpl implements SnapshotTaskService {

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

    @Autowired
    private DefaultSchedulingConfigurer defaultSchedulingConfigurer;
    @Autowired
    private SnapshotTaskRepository snapshotTaskRepository;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private CloudServerService cloudServerService;
    @Autowired
    private CloudServerRepository cloudServerRepository;

    @Override
    public BocloudResult create(String taskUuid, RequestContext context) {
        try {
            SnapshotTask snapshotTask = snapshotTaskRepository.queryByTaskId(taskUuid);
            if (null == snapshotTask) {
                logger.info("定时快照任务不存在,任务启动失败....");
                return new BocloudResult<>(false, "定时快照任务不存在");
            }
            // 等待任务调度初始化完成
            while (!defaultSchedulingConfigurer.inited()) {
                Thread.sleep(5000);
            }
            String taskId = ScheduledTasksConstant.SNAPSHOT + taskUuid;
            defaultSchedulingConfigurer.addTriggerTask(taskId,
                    new TriggerTask(new SnapshotTaskThread(snapshotTask), new CronTrigger(snapshotTask.getCron())),
                    snapshotTask.getCron());
            logger.info("定时快照任务启动成功：云主机ID {}, 表达式{} ", snapshotTask.getServerId(), snapshotTask.getCron());
            return new BocloudResult<>(true, "定时快照任务启动成功！");
        } catch (Exception e) {
            logger.error("定时快照任务不存在,任务启动失败.... ： {}", e.getMessage());
            return new BocloudResult<>(false, "添加定时快照任务失败 ： {}", e.getMessage());
        }
    }

    @Override
    public BocloudResult remove(String taskUuid) {
        try {
        	logger.info("taskUuid :" + taskUuid);
            SnapshotTask snapshotTask = snapshotTaskRepository.queryByTaskId(taskUuid);
            Assert.notNull(snapshotTask, "定时快照任务不存在");
            // 等待任务调度初始化完成
            while (!defaultSchedulingConfigurer.inited()) {
                Thread.sleep(5000);
            }
            String taskId = ScheduledTasksConstant.SNAPSHOT + taskUuid;
            defaultSchedulingConfigurer.cancelTriggerTask(taskId);
            logger.info(snapshotTask.getServerId() + "云主机取消定时快照任务成功！");
            return new BocloudResult<>(true, "云主机取消定时快照任务成功！");
        } catch (Exception e) {
            logger.error("云主机取消定时快照任务失败 ： " + e.getMessage());
            return new BocloudResult<>(false, "云主机取消定时快照任务失败 ： " + e.getMessage());
        }
    }

    @Override
    public BocloudResult removeByVmId(Long serverId) {
        try {
        	logger.info("serverId :" + serverId);
            CloudServer cloudServer = cloudServerRepository.query(serverId);
            Assert.notNull(cloudServer, "云主机不存在");
            List<SnapshotTask> snapshotTasks = snapshotTaskRepository.listByServerId(serverId);
            if (ListTool.isEmpty(snapshotTasks)) {
                return new BocloudResult<>(true, "定时快照任务删除成功");
            }
            for (SnapshotTask snapshotTask : snapshotTasks) {
                BocloudResult remove = this.remove(snapshotTask.getTaskId());
                if (remove.isFailed()) {
                    logger.error("云主机{}取消定时快照任务失败：" + remove.getMessage(), cloudServer.getName());
                    continue;
                }
                snapshotTaskRepository.remove(snapshotTask.getId());
            }
            return new BocloudResult<>(true, "云主机取消定时快照任务成功！");
        } catch (Exception e) {
            logger.error("云主机取消定时快照任务失败 ： " + e.getMessage());
            return new BocloudResult<>(false, "云主机取消定时快照任务失败 ： " + e.getMessage());
        }
    }

    @Override
    public BocloudResult modify(String taskUuid, RequestContext context) {
        try {
        	logger.info("taskUuid :" + taskUuid);
            SnapshotTask snapshotTask = snapshotTaskRepository.queryByTaskId(taskUuid);
            Assert.notNull(snapshotTask, "定时快照任务不存在");
            // 等待任务调度初始化完成
            while (!defaultSchedulingConfigurer.inited()) {
                Thread.sleep(5000);
            }
            String taskId = ScheduledTasksConstant.SNAPSHOT + snapshotTask.getTaskId();
            defaultSchedulingConfigurer.resetTriggerTask(taskId,
                    new TriggerTask(new SnapshotTaskThread(snapshotTask), new CronTrigger(snapshotTask.getCron())),
                    snapshotTask.getCron());
            logger.info("定时快照任务【重置】成功！定时策略 ： " + snapshotTask.getCron());
            return new BocloudResult<>(true, "定时快照任务重置成功！");
        } catch (Exception e) {
            logger.error("重置定时快照任务失败 ： " + e.getMessage());
            return new BocloudResult<>(false, "重置定时快照任务失败 ： " + e.getMessage());
        }
    }

    class SnapshotTaskThread implements Runnable {

        private SnapshotTask snapshotTask;

        public SnapshotTaskThread(SnapshotTask snapshotTask) {
            super();
            this.snapshotTask = snapshotTask;
        }

        @Override
        public void run() {
            String path = "snapshot_task_" + snapshotTask.getTaskId();
            try (BocloudACLock lock = lockFactory.getACLock(path)) {
                Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                // 创建快照
                CloudServer server = cloudServerRepository.query(snapshotTask.getServerId());
                if (null != server) {
                    String name = snapshotTask.getName() == null ? "" : snapshotTask.getName();
                    RequestContext context = new RequestContext(server.getCatalog(), server.getCreatorId(),
                            server.getTenantId(), server.getProjectId(), null);
                    cloudServerService.snapshot(new VmSnapshotParam(snapshotTask.getServerId(),
                            name + "_" + System.currentTimeMillis(), snapshotTask.getRemark(), null,
                            null, null), context);
                }

            } catch (Exception e) {
                logger.error("Get error message：", e);
            }
        }

        public SnapshotTask getSnapshotTask() {
            return snapshotTask;
        }

        public void setSnapshotTask(SnapshotTask snapshotTask) {
            this.snapshotTask = snapshotTask;
        }

    }

}
