package com.bocloud.ims.repository.resource;

import com.bocloud.common.model.Pager;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.SimpleBean;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.database.core.intf.impl.BasicGenericDao;
import com.bocloud.database.utils.QueryBuilder;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.LoadBalancer;
import com.bocloud.ims.entity.resource.Vpc;
import com.bocloud.orm.OrmGenericDaoImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 负载均衡Repository接口实现
 *
 * @author weiwei
 */
@Repository("loadBalancerRepository")
public class LoadBalancerRepository extends OrmGenericDaoImpl<LoadBalancer, Long> {

	public LoadBalancerRepository(JdbcTemplate jdbcTemplate, NamedParameterJdbcTemplate npJdbcTemplate) {
		super(jdbcTemplate, npJdbcTemplate);
	}

	public List<LoadBalancer> list(int page, int rows, List<Param> params, Map<String, String> sorter)
			throws Exception {
		String sql = "select a.*,b.floating_ip_address,b.id fip_id,v.name vendor_name,t.name tenant_name, r.`name` region_name from load_balancer a left join floating_ip b on a.port_id = b.port_id and b.is_deleted = 0 left join cloud_vendor v on a.vendor_id = v.id left join tenant t on a.tenant_id = t.id "
				+ " left join region r on a.vendor_id = r.vendor_id and a.region = r.region_id "
				+ " where  a.is_deleted = 0";
		sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, params, sorter), "a");
		Map<String, Object> paramMap = QueryBuilder.getParam(params);
		return this.list(LoadBalancer.class, sql, paramMap);
	}

	public List<SimpleBean> list(List<Param> params, Map<String, String> sorter) throws Exception {
		String sql = "select a.id,a.name,a.lb_uuid from load_balancer a where a.is_deleted = 0";
		sql = QueryBuilder.build(sql, new Pager(1, Integer.MAX_VALUE, params, sorter), "a");
		Map<String, Object> paramMap = QueryBuilder.getParam(params);
		List<LoadBalancer> balancers = this.list(LoadBalancer.class, sql, paramMap);
		List<SimpleBean> beans = Lists.newArrayList();
		for (LoadBalancer balancer : balancers) {
			beans.add(new SimpleBean(balancer.getId(), balancer.getName(), balancer.getLbUuid()));
		}
		return beans;
	}

	public List<LoadBalancer> listByVid(Long vendorId) throws Exception {
		String sql = "select a.*,t.name tenant_name from load_balancer a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.vendor_id = :vendorId";
		Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
		return this.list(LoadBalancer.class, sql, params);
	}

	public int count(List<Param> params) throws Exception {
		String sql = "select count(1) from load_balancer a where a.is_deleted = 0";
		sql = QueryBuilder.buildRaw(sql, params, null, "a");
		Map<String, Object> paramMap = QueryBuilder.getParam(params);
		return this.countQuery(sql, paramMap).intValue();
	}

	public boolean remove(Long id, Long userId) throws Exception {
		String sql = "update load_balancer set is_deleted = true,gmt_modify = :gmtModify,mender_id = :menderId where is_deleted = 0 and id = :id";
		Map<String, Object> params = MapTools.simpleMap("id", id);
		params.put("menderId", userId);
		params.put("gmtModify", new Date());
		return this.execute(sql, params) > 0;

	}

	public boolean removeByVid(Long vendorId, Long userId) throws Exception {
		String sql = "update load_balancer set is_deleted = true,gmt_modify = :gmtModify,mender_id = :menderId where is_deleted = 0 and vendor_id = :vendorId";
		Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
		params.put("menderId", userId);
		params.put("gmtModify", new Date());
		return this.execute(sql, params) > 0;
	}

	public LoadBalancer query(Long id) throws Exception {
		String sql = "select a.*,b.floating_ip_address,b.id fip_id,t.name tenant_name , r.`name` region_name from load_balancer a left join tenant t on a.tenant_id = t.id left join floating_ip b on a.port_id = b.port_id  and b.is_deleted = 0 "
				+ " left join region r on a.region = r.region_id and a.vendor_id = r.vendor_id "
				+ " where a.is_deleted = 0 and a.id = :id";
		Map<String, Object> params = MapTools.simpleMap(Common.ID, id);
		List<LoadBalancer> list = this.list(LoadBalancer.class, sql, params);
		if (list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}

	public int count(List<Param> params, Long tenantId, List<Long> projectIds) throws Exception {
		String sql = "select count(a.id) from load_balancer a left join floating_ip f on a.port_id = f.port_id and f.is_deleted = 0 left join tenant t on a.tenant_id = t.id left join cloud_vendor v on v.id = a.vendor_id where a.is_deleted = 0";
		Map<String, Object> paramMap = QueryBuilder.getParam(params);
		if (null != tenantId && 0L != tenantId) {
			sql += " and a.tenant_id = :tenantId";
			paramMap.put("tenantId", tenantId);
		}
		if (!ListTool.isEmpty(projectIds)) {
			sql += " and a.project_id in (:projectIds) ";
			paramMap.put("projectIds", projectIds);
		}
		sql = QueryBuilder.buildRaw(sql, params, null, "a");
		return this.countQuery(sql, paramMap).intValue();
	}

	public List<LoadBalancer> list(int page, int rows, List<Param> params, Map<String, String> sorter, Long tenantId,
			List<Long> projectIds) throws Exception {
		String sql = "select a.*,t.name tenant_name,f.floating_ip_address,f.id fip_id,v.name vendor_name from load_balancer a left join floating_ip f on a.port_id = f.port_id and f.is_deleted = 0 left join tenant t on a.tenant_id = t.id left join cloud_vendor v on v.id = a.vendor_id where a.is_deleted = 0";
		Map<String, Object> paramMap = QueryBuilder.getParam(params);
		if (null != tenantId && 0L != tenantId) {
			sql += " and a.tenant_id = :tenantId";
			paramMap.put("tenantId", tenantId);
		}
		if (!ListTool.isEmpty(projectIds)) {
			sql += " and a.project_id in (:projectIds) ";
			paramMap.put("projectIds", projectIds);
		}
		sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, params, sorter), "a");
		return this.list(LoadBalancer.class, sql, paramMap);
	}

	public boolean inUseByTenants(Long vendorId) throws Exception {
		String sql = "select count(1) from load_balancer a where a.is_deleted = 0 and a.tenant_id is not null and a.tenant_id != 0 and a.vendor_id = :vendorId";
		Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
		return this.countQuery(sql, params).intValue() > 0;
	}

	public boolean tenantCheck(Long tenantId, Long projectId, Long creatorId) throws Exception {
		String sql = "select count(1) from load_balancer a where a.is_deleted = 0 ";
		Map<String, Object> paramMap = Maps.newHashMap();
		if (null != tenantId && 0L != tenantId) {
			sql += " and a.tenant_id = :tenantId";
			paramMap.put("tenantId", tenantId);
		}
		if (null != projectId && 0L != projectId) {
			sql += " and a.project_id = :projectId";
			paramMap.put("projectId", projectId);
		}
		if (null != creatorId && 0L != creatorId) {
			sql += " and a.creator_id = :creatorId";
			paramMap.put("creatorId", creatorId);
		}
		return this.countQuery(sql, paramMap).intValue() > 0;
	}

	public boolean removeByVid(Long vendorId, String region, Long userId) throws Exception {
		String sql = "update load_balancer set is_deleted = true,gmt_modify = :gmtModify,mender_id = :menderId where is_deleted = 0 and vendor_id = :vendorId and region = :region";
		Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
		params.put("region", region);
		params.put("menderId", userId);
		params.put("gmtModify", new Date());
		return this.execute(sql, params) > 0;
	}

	public List<LoadBalancer> listByVid(Long vendorId, String region) throws Exception {
		String sql = "select a.*,t.name tenant_name from load_balancer a left join tenant t on a.tenant_id = t.id where a.is_deleted = 0 and a.vendor_id = :vendorId and region = :region ";
		Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
		params.put("region", region);
		return this.list(LoadBalancer.class, sql, params);
	}

	public LoadBalancer queryByUuid(String lbUuid, Long vendorId) {
		String sql = " SELECT a.* FROM  load_balancer a WHERE   a.is_deleted = 0    AND a.vendor_id = :vendorId and a.lb_uuid = :lbUuid ";
		Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
		params.put("lbUuid", lbUuid);
		List<LoadBalancer> list = this.list(LoadBalancer.class, sql, params);
		if (list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}

	public LoadBalancer queryByUuid(String lbUuid) {
		String sql = " select a.* from load_balancer a where a.is_deleted = 0 and a.lb_uuid = :lbUuid ";
		Map<String, Object> params = MapTools.simpleMap("lbUuid", lbUuid);
		List<LoadBalancer> list = this.list(LoadBalancer.class, sql, params);
		if (list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}

	public List<LoadBalancer> getByVpc(Long vpcId, Long vendorId) throws Exception {
		String sql = "select a.* from load_balancer a  where a.is_deleted = 0 and a.vpc_id = :vpcId and a.vendor_id = :vendorId";
		Map<String, Object> params = MapTools.simpleMap("vpcId", vpcId);
		params.put(Common.VENDORID, vendorId);
		return this.list(LoadBalancer.class, sql, params);
	}

	public List<LoadBalancer> listAvailableLbs(Long vendorId, String regionId) {
		String sql = "select a.* from load_balancer a LEFT JOIN elastic_ip b on a.lb_uuid=b.instance_id "
				+ " where a.is_deleted=0 and a.vendor_id = :vendorId and a.region = :regionId and b.instance_id is null ";
		Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
		params.put("regionId", regionId);
		return this.list(LoadBalancer.class, sql, params);
	}
	
	public List<LoadBalancer> listAvailableLbs(Long vendorId, String regionId, Long userId, Long tenantId,
			List<Long> projectIds) {
		String subquerySql = "select a.* from load_balancer a LEFT JOIN elastic_ip b on a.lb_uuid=b.instance_id "
				+ " where a.is_deleted=0 and a.vendor_id = :vendorId and a.region = :regionId and b.instance_id is null ";
		Map<String, Object> paramMap = MapTools.simpleMap(Common.VENDORID, vendorId);
		paramMap.put("regionId", regionId);
		String sql = "select distinct d.* from (" + subquerySql + ") d  where ( 1=-1 ";
		if (null != userId && 0L != userId) {
			sql += " or d.owner_id =:userId or d.mender_id = :userId ";
			paramMap.put("userId", userId);
		}
		if (null != tenantId && 0L != tenantId) {
			sql += " or d.tenant_id = :tenantId";
			paramMap.put("tenantId", tenantId);
		}
		if (null != projectIds && !projectIds.isEmpty()) {
			sql += " or d.project_id in (:projectIds) ";
			paramMap.put("projectIds", projectIds);
		}
		sql += " )";
		return this.list(LoadBalancer.class, sql, paramMap);

	}

	public List<LoadBalancer> getByLabels(String labels) throws Exception {
		String sql = "select a.* from load_balancer a  where a.is_deleted = 0 and a.labels = :labels";
		Map<String, Object> params = MapTools.simpleMap("labels", labels);
		return this.list(LoadBalancer.class, sql, params);
	}

	public int count(Long userId, Long tenantId, List<Long> projectIds, List<Param> params, String vendorType) {
		String subquerySql = "select a.* from load_balancer a left join cloud_vendor c on a.vendor_id = c.id   "
				+ " where a.is_deleted = 0 ";
		if (!StringUtils.isEmpty(vendorType)) {
			subquerySql += " and c.type = '" + vendorType + "'  ";
		}
		Map<String, Object> param = QueryBuilder.getParam(params);
		subquerySql = QueryBuilder.build(subquerySql, params, new HashMap<>(8), "a");
		String sql = "select distinct count(1) from (" + subquerySql + ") c  where ( 1=-1 ";
		if (null != userId && 0L != userId) {
			sql += " or c.owner_id =:userId or c.mender_id = :userId ";
			param.put("userId", userId);
		}
		if (null != tenantId && 0L != tenantId) {
			sql += " or c.tenant_id = :tenantId";
			param.put("tenantId", tenantId);
		}
		if (null != projectIds && !projectIds.isEmpty()) {
			sql += " or c.project_id in (:projectIds) ";
			param.put("projectIds", projectIds);
		}
		sql += ")";
		return this.countQuery(sql, param).intValue();
	}

	public List<LoadBalancer> list(int page, int rows, Long userId, Long tenantId, List<Long> projectIds,
			List<Param> params, Map<String, String> sorter, String vendorType) {
		String subquerySql = "select a.*,b.floating_ip_address,b.id fip_id,v.name vendor_name,t.name tenant_name, r.`name` region_name from load_balancer a left join floating_ip b on a.port_id = b.port_id and b.is_deleted = 0 left join cloud_vendor v on a.vendor_id = v.id left join tenant t on a.tenant_id = t.id "
				+ " left join region r on a.vendor_id = r.vendor_id and a.region = r.region_id "
				+ " where  a.is_deleted = 0";
		if (!StringUtils.isEmpty(vendorType)) {
			subquerySql += " and v.type = '" + vendorType + "'  ";
		}
		subquerySql = QueryBuilder.build(subquerySql, params, new HashMap<>(8), "a");
		Map<String, Object> paramMap = QueryBuilder.getParam(params);
		String sql = "select distinct  d.*  from (" + subquerySql + ") d  where ( 1=-1 ";
		if (null != userId && 0L != userId) {
			sql += " or d.owner_id =:userId or d.mender_id = :userId ";
			paramMap.put("userId", userId);
		}
		if (null != tenantId && 0L != tenantId) {
			sql += " or d.tenant_id = :tenantId";
			paramMap.put("tenantId", tenantId);
		}
		if (null != projectIds && !projectIds.isEmpty()) {
			sql += " or d.project_id in (:projectIds) ";
			paramMap.put("projectIds", projectIds);
		}
		sql += " )";
		sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, null, sorter), "d");
		return this.list(LoadBalancer.class, sql, paramMap);
	}

	public LoadBalancer getByUuid(String uuid) {
		String sql = "select a.* from load_balancer a where a.is_deleted = 0 and a.uuid = :uuid";
		Map<String, Object> paramMap = MapTools.simpleMap("uuid", uuid);
		List<LoadBalancer> list = this.list(LoadBalancer.class, sql, paramMap);
		return ListTool.isEmpty(list) ? null : list.get(0);
	}

}
