package com.bocloud.ims.service.manageone;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.manageone.VdcDriver;
import com.bocloud.cmp.driver.manageone.VdcProjectDriver;
import com.bocloud.cmp.driver.manageone.VdcUserDriver;
import com.bocloud.cmp.model.manageone.VdcModel;
import com.bocloud.cmp.model.manageone.VdcProjectModel;
import com.bocloud.cmp.model.manageone.VdcUserModel;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.entity.common.Tenant;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.manageone.ManageOneAccount;
import com.bocloud.ims.entity.resource.manageone.ManageOneProject;
import com.bocloud.ims.entity.resource.manageone.ManageOneVdc;
import com.bocloud.ims.interfaces.manageone.ManageOneAccountService;
import com.bocloud.ims.repository.manageone.ManageOneAccountRepository;
import com.bocloud.ims.repository.manageone.ManageOneProjectRepository;
import com.bocloud.ims.repository.manageone.ManageOneVdcRepository;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.service.internal.SmsTenantService;
import com.bocloud.ims.service.utils.PasswordGenerator;
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.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * manage one账号管理
 *
 * @author wangyu
 * @version 1.0
 * @since 2020年6月17日
 */
@Service("manageOneAccountService")
public class ManageOneAccountServiceImpl implements ManageOneAccountService {

	private static Logger logger = LoggerFactory.getLogger(ManageOneAccountServiceImpl.class);
	@Autowired
	private CloudVendorRepository vendorRepository;
	@Autowired
	private VdcDriver vdcDriver;
	@Autowired
	private VdcProjectDriver vdcProjectDriver;
	@Autowired
	private VdcUserDriver vdcUserDriver;
	@Autowired
	private ManageOneVdcRepository vdcRepository;
	@Autowired
	private ManageOneProjectRepository projectRepository;
	@Autowired
	private ManageOneAccountRepository accountRepository;
	@Autowired
	private SmsTenantService smsTenantService;
	@Autowired
	private LockFactory lockFactory;

	@Override
	public BocloudResult createAccount(Long vendorId, Long tenantId, RequestContext context) {
		String path = ManageOneAccount.class.getSimpleName() + "_" + tenantId;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			CloudVendor vendor = vendorRepository.query(vendorId);
			Assert.notNull(vendor, "云平台不存在");
			BocloudResult<Tenant> result = smsTenantService.detail(tenantId);
			Assert.isTrue(result.isSuccess(), "租户不存在");
			Tenant tenant = result.getData();
			Assert.notNull(tenant, "租户不存在");
			ManageOneVdc manageOneVdc = vdcRepository.queryByTenantId(tenantId);
			// 未查到老数据就创建一个新的vdc
			if (null == manageOneVdc) {
				ManageOneVdc upperVdc = null;
				if (null != tenant.getParentId() && 0L != tenant.getParentId()) {
					BocloudResult<Tenant> parentResult = smsTenantService.detail(tenant.getParentId());
					Assert.isTrue(parentResult.isSuccess(), "父租户不存在");
					Tenant parent = parentResult.getData();
					Assert.notNull(parent, "父租户不存在");
					upperVdc = vdcRepository.queryByTenantId(parent.getId());
				}
				VdcModel vdcModel = new VdcModel();
				vdcModel.setUpperVdcId(null == upperVdc ? "0" : upperVdc.getVdcId());
				vdcModel.setName(tenant.getAccount() + "_VDC_" + System.currentTimeMillis());
				BocloudResult vdcResult = null;
				if (!"0".equals(vdcModel.getUpperVdcId())) {
					ManageOneAccount parentAccount = accountRepository.queryByTenantId(tenant.getParentId(), vendorId);
					Assert.notNull(parentAccount, "父级租户账号不存在");
					vdcResult = vdcDriver.create(vendor.getUuid(), parentAccount.getUsername(),
							parentAccount.getPassword(), parentAccount.getProjectId(), parentAccount.getDomainName(),
							vdcModel);
				} else {
					vdcResult = vdcDriver.create(vendor.getUuid(), vdcModel);
				}
				Assert.isTrue(vdcResult.isSuccess(), vdcResult.getMessage());
				manageOneVdc = new ManageOneVdc();
				BeanUtils.copyProperties(
						JSONObject.parseObject(JSONObject.toJSONString(vdcResult.getData()), VdcModel.class),
						manageOneVdc);
				manageOneVdc.setVendorId(vendorId);
				manageOneVdc.setParentId(null == upperVdc ? 0L : upperVdc.getId());
				manageOneVdc.setTenantId(tenantId);
				vdcRepository.save(manageOneVdc);
			}
			// 创建vdc下项目
			List<ManageOneProject> projects = projectRepository.listByVdcId(manageOneVdc.getId());
			ManageOneProject project = null;
			if (!ListTool.isEmpty(projects)) {
				project = projects.get(0);
			} else {
				VdcProjectModel projectModel = new VdcProjectModel();
				projectModel.setName(tenant.getAccount() + "_PROJECT_" + System.currentTimeMillis());
				projectModel.setEnabled(true);
				projectModel.setShared(false);
				projectModel.setVdcTenantId(manageOneVdc.getVdcId());
				projectModel.setIsBindExternalNetwork(true);
				BocloudResult projectResult = null;
				if (!"0".equals(manageOneVdc.getUpperVdcId())) {
					ManageOneAccount parentAccount = accountRepository.queryByTenantId(tenant.getParentId(), vendorId);
					Assert.notNull(parentAccount, "父级租户账号不存在");
					projectResult = vdcProjectDriver.create(vendor.getUuid(), parentAccount.getUsername(),
							parentAccount.getPassword(), parentAccount.getProjectId(), parentAccount.getDomainName(),
							projectModel);
				} else {
					projectResult = vdcProjectDriver.create(vendor.getUuid(), projectModel);
				}
				Assert.isTrue(projectResult.isSuccess(), projectResult.getMessage());
				project = new ManageOneProject();
				BeanUtils.copyProperties(
						JSONObject.parseObject(JSONObject.toJSONString(projectResult.getData()), VdcProjectModel.class),
						project);
				project.setVdcId(manageOneVdc.getId());
				project.setVendorId(vendorId);
				projectRepository.save(project);
			}
			String password = new PasswordGenerator(10, 4).generateRandomPassword();
			// 创建用户
			VdcUserModel model = new VdcUserModel();
			model.setVdcId(manageOneVdc.getVdcId());
			model.setName(tenant.getAccount() + "_USER_" + System.currentTimeMillis());
			model.setPassword(password);
			List<String> projectList = new ArrayList<>();
			projectList.add(project.getProjectId());
			model.setProjects(projectList);
			List<String> roleList = new ArrayList<>();
			roleList.add("00000000-0000-0000-0000-000000000001");
			model.setRoleList(roleList);
			BocloudResult userResult = null;
			if (!"0".equals(manageOneVdc.getUpperVdcId())) {
				ManageOneAccount parentAccount = accountRepository.queryByTenantId(tenant.getParentId(), vendorId);
				Assert.notNull(parentAccount, "父级租户账号不存在");
				userResult = vdcUserDriver.create(vendor.getUuid(), parentAccount.getUsername(),
						parentAccount.getPassword(), parentAccount.getProjectId(), parentAccount.getDomainName(),
						model);
			} else {
				userResult = vdcUserDriver.create(vendor.getUuid(), model);
			}
			Assert.isTrue(userResult.isSuccess(), userResult.getMessage());
			VdcUserModel vdcUserModel = JSONObject.parseObject(JSONObject.toJSONString(userResult.getData()),
					VdcUserModel.class);
			ManageOneAccount account = new ManageOneAccount();
			account.setDomainName(vdcUserModel.getDomainName());
			account.setUsername(vdcUserModel.getName());
			account.setPassword(password);
			account.setProjectId(project.getProjectId());
			account.setUserId(vdcUserModel.getUserId());
			account.setTenantId(tenantId);
			account.setVdcId(manageOneVdc.getId());
			account.setVendorId(vendor.getId());
			JSONObject authentication = JSONObject.parseObject(vendor.getAuthentication());
			account.setUrl(authentication.getString("address"));
			accountRepository.save(account);
			return new BocloudResult(true, account, "创建成功");
		} catch (Exception e) {
			logger.error("Get error message：{}", e.getMessage());
			return new BocloudResult(false, e.getMessage());
		}
	}

	@Override
	public ManageOneAccount queryAccount(Long vendorId, Long tenantId) {
		try {
			ManageOneAccount account = accountRepository.queryByTenantId(tenantId, vendorId);
			if (null == account) {
				// 创建账号
				BocloudResult result = this.createAccount(vendorId, tenantId, null);
				Assert.isTrue(result.isSuccess(), result.getMessage());
				account = (ManageOneAccount) result.getData();
			}
			return account;
		} catch (Exception e) {
			logger.error("Get error message：{}", e.getMessage());
			return null;
		}
	}

	@Override
	public BocloudResult removeAccount(Long vendorId, Long tenantId) {
		try {
			CloudVendor vendor = vendorRepository.query(vendorId);
			Assert.notNull(vendor, "云平台不存在");
			ManageOneAccount account = accountRepository.queryByTenantId(tenantId, vendorId);
			if (null != account) {
				String path = ManageOneAccount.class.getSimpleName() + "_" + tenantId;
				try (BocloudACLock lock = lockFactory.getACLock(path)) {
					Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
					BocloudResult result = vdcUserDriver.remove(vendor.getUuid(), account.getUserId());
					Assert.isTrue(result.isSuccess(), result.getMessage());
					// 删除项目
					result = vdcProjectDriver.remove(vendor.getUuid(), account.getProjectId());
					Assert.isTrue(result.isSuccess(), result.getMessage());
					projectRepository.removeByProjectId(account.getProjectId(), vendorId);
					// 删除vdc
					ManageOneVdc vdc = vdcRepository.query(account.getVdcId());
					if (null != vdc) {
						result = vdcDriver.remove(vendor.getUuid(), vdc.getVdcId());
						Assert.isTrue(result.isSuccess(), result.getMessage());
						vdcRepository.remove(vdc.getId());
					}
				} catch (Exception e) {
					logger.error("Get error message：{}", e.getMessage());
					return new BocloudResult(false, e.getMessage());
				}
			}
			return new BocloudResult(true, "查询成功");
		} catch (Exception e) {
			logger.error("Get error message：{}", e.getMessage());
			return new BocloudResult(false, e.getMessage());
		}
	}

}
