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

import com.bocloud.cmp.driver.common.TaskMsgDriver;
import com.bocloud.cmp.driver.compute.ServerDriver;
import com.bocloud.cmp.driver.compute.SnapshotDriver;
import com.bocloud.cmp.entity.enums.BocloudStatus;
import com.bocloud.cmp.model.SnapshotModel;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.OperateResult;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.Server;
import com.bocloud.ims.entity.resource.Snapshot;
import com.bocloud.ims.interfaces.h3c.H3cSnapshotService;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.ServerRepository;
import com.bocloud.ims.repository.resource.SnapshotRepository;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
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.stereotype.Service;
import org.springframework.util.Assert;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service("h3cSnapshotService")
public class H3cSnapshotServiceImpl extends H3cCommonService implements H3cSnapshotService {
	Logger logger = LoggerFactory.getLogger(this.getClass());

	@Autowired
	private CloudVendorRepository cloudVendorRepository;

	@Autowired
	private SnapshotDriver snapshotDriver;

	@Autowired
	private TaskMsgDriver taskMsgDriver;

	@Autowired
	private SnapshotRepository snapshotRepository;

	@Autowired
	private ResourceEventPublisher resourceEventPublisher;

	@Autowired
	private ServerDriver serverDriver;

	@Autowired
	private LockFactory lockFactory;

	@Autowired
	private CloudServerRepository cloudServerRepository;

	@Autowired
	private ServerRepository serverRepository;

	private static OperateResult.OperateCategory operateCategory = OperateResult.OperateCategory.ResourceEvent;

	@Override
	public BocloudResult<String> create(Snapshot snapshotParam, RequestContext context) {
		Assert.notNull(snapshotParam, "参数格式错误");
		Long serverId = snapshotParam.getServerId();
		String path = CloudServer.class.getSimpleName() + "_" + serverId;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			Long userId = context.getTarget();
			Long tenantId = context.getTenant();
			String name = snapshotParam.getName();
			String remark = snapshotParam.getRemark();
			CloudServer server = cloudServerRepository.query(serverId);
			Assert.notNull(server, "虚拟机不存在！");
			CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
			Assert.notNull(vendor, "云供应商不存在！");
			Server host = serverRepository.query(server.getHostId());
			Assert.notNull(host, "宿主机不存在");
			if (null != host.getMaintained() && host.getMaintained()) {
				return new BocloudResult<String>(false, "该虚拟机所在宿主机处于维护模式下，无法执行创建快照任务");
			}
			SnapshotModel model = new SnapshotModel(name, remark, null, server.getInstanceId());
			new Thread(() -> {
				String operate = vendor.getType().toLowerCase() + ".vm.snapshot";
				try {
					BocloudResult result = serverDriver.snapshot(model, vendor.getUuid(), null);
					if (result.isSuccess()) {
						Snapshot snapshot = new Snapshot();
						snapshot.preSave(userId, userId, server.getVendorId(), serverId, tenantId);
						snapshot.setName(name);
						snapshot.setRemark(remark);
						snapshot.setCreateTime(new Date());
						snapshot.setStatus("AVAILABLE");
						snapshot.setSnapshotType("VM");
						snapshot.setSnapshotVal(name);
						snapshotRepository.save(snapshot);
					}
					resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(), operate,
							MapTools.simpleMap(Common.VENDORID, vendor.getId()), operateCategory, context));
				} catch (Exception e) {
					logger.error("Get Message Exception:", e);
					resourceEventPublisher.send(new OperateResult(false, "快照创建失败：" + e.getMessage(), operate,
							MapTools.simpleMap(Common.VENDORID, vendor.getId()), operateCategory, context));
				}
			}).start();
			return new BocloudResult<String>(true, "创建任务已经下发，正在执行……");
		} catch (Exception e) {
			logger.error("快照创建失败：" + e.getMessage());
			return new BocloudResult<String>(false, "快照创建失败：" + e.getMessage());
		}
	}

	@Override
	public BocloudResult<String> remove(Long id, RequestContext context) {
		String path = Snapshot.class.getSimpleName() + "_" + id;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			Snapshot snap = snapshotRepository.query(id);
			if (null == snap) {
				logger.warn("snapshot data not exist");
				return new BocloudResult<String>(false, "数据不存在", "", "");
			}
			// 云供应商
			CloudVendor vendor = cloudVendorRepository.query(snap.getVendorId());
			if (null == vendor) {
				return new BocloudResult<String>(false, "获取云供应商失败");
			}
			CloudServer server = cloudServerRepository.query(snap.getVmId());
			if (null == server) {
				logger.warn("CloudServer data not exist");
				return new BocloudResult<String>(false, "虚拟机不存在");
			}
			SnapshotModel model = new SnapshotModel();
			model.setName(snap.getName());
			model.setInstanceId(server.getInstanceId());
			// 启动一个线程从MQ上获取数据
			new Thread(new Runnable() {
				@Override
				public void run() {
					String operate = vendor.getType().toLowerCase() + ".snapshot";
					try {
						BocloudResult result = snapshotDriver.remove(vendor.getUuid(), null, model);
						String content = "快照【" + snap.getName() + "】删除失败";
						if (result.isSuccess()) {
							snapshotRepository.remove(id, context.getTarget());
							content = "快照【" + snap.getName() + "】删除成功";
						} else {
							content = "快照删除失败：" + result.getMessage();
						}
						resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
								MapTools.simpleMap("vendorId", vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
					} catch (Exception e) {
						logger.error("remove snapshot fail :" + e.getMessage());
						resourceEventPublisher
								.send(new OperateResult(false, "快照【" + snap.getName() + "】删除失败:" + e.getMessage(),
										operate, MapTools.simpleMap("vendorId", vendor.getId()),
										OperateResult.OperateCategory.ResourceEvent, context));
					}
				}
			}).start();
			return new BocloudResult<String>(true, "删除任务已经下发，正在执行……");
		} catch (Exception e) {
			logger.error("remove snapshot fail:", e);
			return new BocloudResult<String>(false, "删除失败", "", "");
		}
	}

	@Override
	public BocloudResult<String> revert(Long id, RequestContext context) {
		String path = Snapshot.class.getSimpleName() + "_" + id;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			Snapshot snap = snapshotRepository.query(id);
			Assert.notNull(snap, "数据不存在");
			// 云供应商
			CloudVendor vendor = cloudVendorRepository.query(snap.getVendorId());
			Assert.notNull(vendor, "获取云供应商失败");
			CloudServer server = cloudServerRepository.query(snap.getVmId());
			Assert.notNull(server, "虚拟机不存在");
			SnapshotModel model = new SnapshotModel();
			model.setInstanceId(server.getInstanceId());
			model.setName(snap.getName());
			// 启动一个线程从MQ上获取数据
			new Thread(() -> {
				String operate = vendor.getType().toLowerCase() + ".snapshot";
				try {
					BocloudResult msgResult = snapshotDriver.revert(vendor.getUuid(), null, model);
					if (msgResult.isSuccess()) {
						server.setStatus(BocloudStatus.Server.STOPPED.name());
						cloudServerRepository.update(server);
						resourceEventPublisher.send(new OperateResult(true, "快照回复成功！", operate,
								MapTools.simpleMap("vendorId", vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
					} else {
						resourceEventPublisher.send(new OperateResult(false, "恢复当前快照失败:" + msgResult.getMessage(),
								operate, MapTools.simpleMap("vendorId", vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
					}
				} catch (Exception e) {
					logger.error("revert snapshot fail :" + e.getMessage());
					resourceEventPublisher.send(new OperateResult(false, "恢复快照失败：" + e.getMessage(), operate,
							MapTools.simpleMap("vendorId", vendor.getId()), OperateResult.OperateCategory.ResourceEvent,
							context));
				}
			}).start();
			return new BocloudResult<String>(true, "恢复快照任务已经下发，正在执行……");
		} catch (Exception e) {
			logger.error("revert snapshot fail:", e);
			return new BocloudResult<String>(false, "恢复当前快照失败：" + e.getMessage());
		}
	}

	private BocloudResult validateH3cSnapshot(Snapshot snap, SnapshotModel snapshotModel) throws Exception {
		CloudServer server = cloudServerRepository.query(snap.getVmId());
		if (null == server) {
			logger.warn("CloudServer data not exist");
			return new BocloudResult(false, "虚拟机不存在");
		}
		Server host = serverRepository.query(server.getHostId());
		if (null == host) {
			logger.warn("HostSystem data not exist");
			return new BocloudResult(false, "宿主机不存在");
		}
		snapshotModel.setInstanceId(server.getInstanceId());
		snapshotModel.setName(snap.getName());
		return new BocloudResult(true, "");
	}

	@Override
	protected ResourceEventPublisher getResourceEventPublisher() {
		return this.resourceEventPublisher;
	}

	@Override
	protected TaskMsgDriver getTaskMsgDriver() {
		return this.taskMsgDriver;
	}

}
