package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.network.VpnConnDriver;
import com.bocloud.cmp.entity.enums.BocloudStatus;
import com.bocloud.cmp.model.VpnConnModel;
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.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.OSTenant;
import com.bocloud.ims.entity.resource.Router;
import com.bocloud.ims.entity.resource.RouterSubnet;
import com.bocloud.ims.entity.resource.Subnet;
import com.bocloud.ims.entity.resource.Vpn;
import com.bocloud.ims.entity.resource.VpnConn;
import com.bocloud.ims.entity.resource.VpnPolicy;
import com.bocloud.ims.interfaces.resource.VpnConnService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.OSTenantRepository;
import com.bocloud.ims.repository.resource.RouterRepository;
import com.bocloud.ims.repository.resource.RouterSubnetRepository;
import com.bocloud.ims.repository.resource.SubnetRepository;
import com.bocloud.ims.repository.resource.VpnConnRepository;
import com.bocloud.ims.repository.resource.VpnPolicyRepository;
import com.bocloud.ims.repository.resource.VpnRepository;
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.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

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

@Service("vpnConnService")
public class VpnConnServiceImpl implements VpnConnService {

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

	@Autowired
	private VpnConnRepository vpnConnRepository;
	@Autowired
	private LockFactory lockFactory;
	@Autowired
	private CloudVendorRepository cloudVendorRepository;
	@Autowired
	private VpnConnDriver vpnConnDriver;
	@Autowired
	private ResourceEventPublisher resourceEventPublisher;
	@Autowired
	private VpnRepository vpnRepository;
	@Autowired
	private VpnPolicyRepository vpnPolicyRepository;
	@Autowired
	private RouterRepository routerRepository;
	@Autowired
	private SubnetRepository subnetRepository;
	@Autowired
	private RouterSubnetRepository routerSubnetRepository;
	@Autowired
	private OSTenantRepository osTenantRepository;

	@Override
	public BocloudResult<GridBean<VpnConn>> list(Pager pager, RequestContext context) {
		try {
			Long tenantId = context.getTenant();
			int total = this.vpnConnRepository.count(pager.getParams(), tenantId);
			List<VpnConn> list = this.vpnConnRepository.list(pager.getPage(), pager.getRows(), pager.getParams(),
					pager.getSorter(), tenantId);
			GridBean gridBean = GridHelper.getBean(pager.getPage(), pager.getRows(), total, list);
			return new BocloudResult<>(true, gridBean, "查询成功");
		} catch (Exception e) {
			logger.error("Query error:", e);
			return new BocloudResult<>(false, "查询失败");
		}
	}

	@Override
	public BocloudResult<String> create(VpnConn vpnConn, RequestContext context) {
		try {
			if (null == vpnConn) {
				return new BocloudResult<>(false, "数据错误！");
			}
			Long vendorId = vpnConn.getVendorId();
			CloudVendor vendor = cloudVendorRepository.query(vendorId);
			if (null == vendor) {
				return new BocloudResult<>(false, "平台数据错误！");
			}
			Vpn vpn = vpnRepository.query(vpnConn.getVpnId());
			if (null == vpn) {
				return new BocloudResult<>(false, "vpn数据不存在！");
			}
			VpnPolicy vpnIkePolicy = vpnPolicyRepository.query(vpnConn.getIkeId());
			if (null == vpnIkePolicy) {
				return new BocloudResult<>(false, "IKE策略数据不存在");
			}
			VpnPolicy vpnIPsecPolicy = vpnPolicyRepository.query(vpnConn.getIpsecId());
			if (null == vpnIPsecPolicy) {
				return new BocloudResult<>(false, "IPSEC策略数据不存在");
			}
			VpnConnModel vpnConnModel = JSON.parseObject(JSON.toJSONString(vpnConn), VpnConnModel.class);
			vpnConnModel.setAdminStateUp(true);
			vpnConnModel.setIkeUuid(vpnIkePolicy.getPolicyUuid());
			vpnConnModel.setIpsecUuid(vpnIPsecPolicy.getPolicyUuid());
			vpnConnModel.setVpnUuid(vpn.getVpnUuid());
			JSONObject dpd = new JSONObject(); // mtu 1500
			dpd.put("action", "hold");
			dpd.put("interval", 300);
			dpd.put("timeout", 1200);
			vpnConnModel.setDpd(JSON.toJSONString(dpd));
			vpnConnModel.setMtu("1500");
			if (null == vpnConnModel.getPsk()) {
				vpnConnModel.setPsk("1QAZ2wsx.");
			}
			vpnConnModel.setInitiator("bi-directional");
			VpnConn vpnConnInfo = new VpnConn();
			BeanUtils.copyProperties(vpnConnModel, vpnConnInfo);
			vpnConnInfo.setTenantId(context.getTenant());
			vpnConnInfo.setGmtModify(new Date());
			vpnConnInfo.setCreatorId(context.getTarget());
			vpnConnInfo.setMenderId(context.getTarget());
			vpnConnInfo.setStatus(BocloudStatus.Server.BUILDING.name());
			vpnConnInfo.setOwnerId(context.getTarget());
			vpnConnRepository.save(vpnConnInfo);
			new Thread(() -> {
				BocloudResult bocloudResult = new BocloudResult<>(false, "创建失败！");
				String content = "创建站点连接成功!";
				try {
					bocloudResult = vpnConnDriver.create(vpnConnModel, vendor.getUuid(), vpnConnModel.getOsTenantName(),
							null);
					if (bocloudResult.isSuccess()) {
						VpnConnModel model = (VpnConnModel) bocloudResult.getData();
						vpnConn.setStatus("RUNNING");
						vpnConn.setVpnConnUuid(model.getVpnConnUuid());
						// 保存路由和子网关系
						Router router = routerRepository.query(vpn.getRouterId());
						Subnet subnet = subnetRepository.query(vpn.getSubnetId());
						if (null != router && null != subnet) {
							RouterSubnet routerSubnet = new RouterSubnet(router.getId(), subnet.getId(),
									vendor.getId());
							routerSubnetRepository.save(routerSubnet);
						}
					} else {
						vpnConn.setStatus(BocloudStatus.Server.EXCEPTION.name());
						content = bocloudResult.getMessage();
					}
					vpnConnRepository.update(vpnConn);
				} catch (Exception e) {
					content = e.getMessage();
				}
				String operate = vendor.getType().toLowerCase() + ".vpnConn";
				resourceEventPublisher.send(new OperateResult(bocloudResult.isSuccess(), content, operate,
						MapTools.simpleMap(Common.VENDORID, vendor.getId()),
						OperateResult.OperateCategory.ResourceEvent, context));
			}).start();
			return new BocloudResult<>(true, "任务已经下发，正在执行....");
		} catch (Exception e) {
			logger.error("create vpn conn fail:", e);
			return new BocloudResult<>(false, "新增失败");
		}
	}

	@Override
	public BocloudResult<String> modify(VpnConn conn, RequestContext context) {
		try {
			VpnConn vpnConn = vpnConnRepository.query(conn.getId());
			if (null == vpnConn) {
				logger.warn("certificate data not exist");
				return new BocloudResult<>(false, "数据不存在");
			}
			CloudVendor vendor = cloudVendorRepository.query(vpnConn.getVendorId());
			if (null == vendor) {
				return new BocloudResult<>(false, "平台数据错误！");
			}
			new Thread(() -> {
				BocloudResult bocloudResult = new BocloudResult<>(false, "编辑失败！");
				String content = "编辑成功!";
				try {
					VpnConnModel model = new VpnConnModel();
					BeanUtils.copyProperties(conn, model);
					bocloudResult = vpnConnDriver.modify(model, vendor.getUuid(), null);
					if (bocloudResult.isSuccess()) {
						VpnConnModel vpnConnModel = (VpnConnModel) bocloudResult.getData();
						BeanUtils.copyProperties(vpnConnModel, vpnConn);
						vpnConn.setVendorId(vpnConn.getVendorId());
						vpnConn.setGmtModify(new Date());
						vpnConn.setStatus("NORMAL");
						vpnConnRepository.update(vpnConn);
					} else {
						content = bocloudResult.getMessage();
					}
				} catch (Exception e) {
					content = e.getMessage();
				}
				String operate = vendor.getType().toLowerCase() + ".vpnConn";
				resourceEventPublisher.send(new OperateResult(bocloudResult.isSuccess(), content, operate,
						MapTools.simpleMap(Common.VENDORID, vendor.getId()),
						OperateResult.OperateCategory.ResourceEvent, context));
			}).start();
			return new BocloudResult<>(true, "任务已经下发，正在执行....");
		} catch (Exception e) {
			logger.error("query volume detail fail:", e);
			return new BocloudResult<>(false, "查询详情失败");
		}
	}

	@Override
	public BocloudResult<String> remove(Long id, RequestContext context) {
		String path = Vpn.class.getSimpleName() + "_" + id;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			VpnConn vpnConn = vpnConnRepository.query(id);
			if (null == vpnConn) {
				logger.warn("certificate data not exist");
				return new BocloudResult<>(false, "数据不存在");
			}
			CloudVendor vendor = cloudVendorRepository.query(vpnConn.getVendorId());
			if (null == vendor) {
				return new BocloudResult<>(false, "平台数据错误！");
			}
			new Thread(() -> {
				BocloudResult bocloudResult = new BocloudResult<>(false, "删除失败！");
				String content = "删除成功!";
				try {
					bocloudResult = vpnConnDriver.remove(vpnConn.getVpnConnUuid(), vendor.getUuid(), null);
					if (bocloudResult.isSuccess()) {
						vpnConnRepository.remove(id, context.getTarget());
						// 删除路由子网关系
						Vpn vpn = vpnRepository.query(vpnConn.getVpnId());
						if (null != vpn) {
							Router router = routerRepository.query(vpn.getRouterId());
							Subnet subnet = subnetRepository.query(vpn.getSubnetId());
							routerSubnetRepository.remove(router.getId(), subnet.getId(), vendor.getId());
						}
						content = "删除成功！";
					} else {
						content = bocloudResult.getMessage();
					}
				} catch (Exception e) {
					content = e.getMessage();
				}
				String operate = vendor.getType().toLowerCase() + ".vpnConn";
				resourceEventPublisher.send(new OperateResult(bocloudResult.isSuccess(), content, operate,
						MapTools.simpleMap(Common.VENDORID, vendor.getId()),
						OperateResult.OperateCategory.ResourceEvent, context));
			}).start();
			return new BocloudResult<>(true, "任务已经下发，正在执行....");
		} catch (Exception e) {
			logger.error("delete certificate fail:", e);
			return new BocloudResult<>(false, "修改失败");
		}
	}

	@Override
	public BocloudResult<VpnConn> detail(Long id) {
		try {
			VpnConn vpnConn = vpnConnRepository.query(id);
			if (null == vpnConn) {
				logger.warn("vpn conn data not exist");
				return new BocloudResult<>(false, "数据不存在");
			}
			if (!org.springframework.util.StringUtils.isEmpty(vpnConn.getTenantUuid())) {
				OSTenant osTenant = osTenantRepository.getByTenantUuid(vpnConn.getTenantUuid(), vpnConn.getVendorId());
				if (null != osTenant) {
					vpnConn.setOsTenantName(osTenant.getName());
				}
			}
			return new BocloudResult<>(true, vpnConn, "查询详情成功");
		} catch (Exception e) {
			logger.error("query volume detail fail:", e);
			return new BocloudResult<>(false, "查询详情失败");
		}
	}

	@Override
	public BocloudResult<String> removeVpnConn(String params, RequestContext context) {
		JSONObject object = JSONObject.parseObject(params);
		Long id = object.getLong("id");
		String path = VpnConn.class.getSimpleName() + "_" + id;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			VpnConn vpnConn = vpnConnRepository.query(id);
			if (null == vpnConn) {
				logger.warn("vpnConn data not exist");
				return new BocloudResult<>(false, "数据不存在");
			}
			CloudVendor vendor = cloudVendorRepository.query(vpnConn.getVendorId());
			if (null == vendor) {
				return new BocloudResult<>(false, "平台数据错误！");
			}
			new Thread(() -> {
				BocloudResult bocloudResult = new BocloudResult<>(false, "删除失败！");
				String content = "删除成功!";
				try {
					bocloudResult = vpnConnDriver.remove(vpnConn.getVpnConnUuid(), vendor.getUuid(), null);
					if (bocloudResult.isSuccess()) {
						vpnConnRepository.remove(id, context.getTarget());
						content = "删除成功！";
					} else {
						content = bocloudResult.getMessage();
					}
				} catch (Exception e) {
					content = e.getMessage();
				}
				String operate = vendor.getType().toLowerCase() + ".vpnConn";
				resourceEventPublisher.send(new OperateResult(bocloudResult.isSuccess(), content, operate,
						MapTools.simpleMap(Common.VENDORID, vendor.getId()),
						OperateResult.OperateCategory.ResourceEvent, context));
			}).start();
			return new BocloudResult<>(true, "任务已经下发，正在执行....");
		} catch (Exception e) {
			logger.error("delete certificate fail:", e);
			return new BocloudResult<>(false, "修改失败");
		}

	}

}
