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.IDFactory;
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.Network;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
import org.apache.commons.lang3.StringUtils;

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

/**
 * 网络数据访问
 * 
 * @author wangyu
 * @version 1.0
 * @since 2020年5月15日
 *
 */
@Repository("networkRepository")
public class NetworkRepository extends BasicGenericDao<Network, Long> {

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

	@Override
	public void save(Network network) {
		network.setGuid(IDFactory.instance().uuid());
		super.save(network);
	}

	public List<Network> list(int page, int rows, List<Param> params, Map<String, String> sorter) {
		String sql = "select a.*,b.name vdc_name,c.name vendor_name, c.type vendor_type from network a "
				+ " left join vdc b on a.vdc_id = b.id "
				+ " left join cloud_vendor c on a.vendor_id = c.id where a.is_deleted = 0";
		sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, params, sorter), "a");
		return this.list(Network.class, sql);
	}

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

	public boolean remove(Long id, Long userId) {
		String sql = "update network set is_deleted = 1, gmt_modify = :gmtModify, mender_id = :menderId where id = :id";
		Map<String, Object> params = MapTools.simpleMap(Common.ID, id);
		params.put("gmtModify", new Date());
		params.put("menderId", userId);
		return this.execute(sql, params) > 0;
	}

	public boolean remove(String name, String type, Long vdcId, Long userId) {
		String sql = "update network set is_deleted = 1, gmt_modify = :gmtModify, mender_id = :menderId where is_deleted = 0 and name = :name and type = :type and vdc_id = :vdcId";
		Map<String, Object> params = MapTools.simpleMap("vdcId", vdcId);
		params.put("gmtModify", new Date());
		params.put("menderId", userId);
		params.put("name", name);
		params.put("type", type);
		return this.execute(sql, params) > 0;
	}

	public Network query(Long id) {
		String sql = "select a.*,b.name vdc_name,v.name vendor_name from network a left join vdc b on a.vdc_id = b.id left join cloud_vendor v on a.vendor_id = v.id where a.is_deleted = 0 and a.id = :id";
		Map<String, Object> params = MapTools.simpleMap(Common.ID, id);
		List<Network> list = this.list(Network.class, sql, params);
		if (list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}

	public List<Network> listByVid(Long vendorId) {
		String sql = "select a.*,b.name vdc_name from network a left join vdc b on a.vdc_id = b.id where a.is_deleted = 0 and a.vendor_id =:vendorId";
		Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
		return this.list(Network.class, sql, params);
	}

	public Network getByNetId(String networkUuid) {
		String sql = "select a.* from network a where a.is_deleted = 0 and a.network_uuid = :networkUuid";
		Map<String, Object> param = MapTools.simpleMap("networkUuid", networkUuid);
		List<Network> list = this.list(Network.class, sql, param);
		if (list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}
	
	public Network getByNetId(String networkUuid, Long vendorId) {
		String sql = "select a.* from network a where a.is_deleted = 0 and a.network_uuid = :networkUuid and a.vendor_id = :vendorId ";
		Map<String, Object> param = MapTools.simpleMap("networkUuid", networkUuid);
		param.put("vendorId", vendorId);
		List<Network> list = this.list(Network.class, sql, param);
		if (list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}

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

	public boolean removeByTenant(long tenantId) {
		String sql = "delete from os_tenant where tenant_id = :tenantId";
		Map<String, Object> params = MapTools.simpleMap("tenantId", tenantId);
		return this.execute(sql, params) > 0;
	}

	public boolean removeByNetworkUuid(String networkUuid, Long userId) {
		String sql = "update network set is_deleted = 1, gmt_modify = :gmtModify, mender_id = :menderId where network_uuid = :networkUuid";
		Map<String, Object> params = MapTools.simpleMap("networkUuid", networkUuid);
		params.put("menderId", userId);
		params.put("gmtModify", new Date());
		return this.execute(sql, params) > 0;
	}

	public List<SimpleBean> list(List<Param> params, Map<String, String> sorter, Long tenantId) {
		String sql = "";
		if (null != tenantId && 0L != tenantId) {
			sql = "select a.id,a.name,a.network_uuid from network a where a.is_deleted = 0 and a.id in(select b.network_id from tenant_network b where b.tenant_id ="
					+ tenantId + ")";
		} else {
			sql = "select a.id,a.name,a.network_uuid from network 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<Network> networks = this.list(Network.class, sql, paramMap);
		List<SimpleBean> beans = new ArrayList<>();
		for (Network network : networks) {
			beans.add(new SimpleBean(network.getId(), network.getName(), network.getNetworkUuid()));
		}
		return beans;
	}

	public List<Network> listByVdc(Long vdcId) {
		String sql = "select a.* from network a where a.is_deleted = 0 and a.vdc_id = :vdcId";
		Map<String, Object> params = MapTools.simpleMap("vdcId", vdcId);
		return this.list(Network.class, sql, params);
	}

	public boolean removeByVdc(Long vdcId, Long userId) {
		String sql = "update network set is_deleted = 1, gmt_modify = :gmtModify, mender_id = :menderId where vdc_id = :vdcId";
		Map<String, Object> params = MapTools.simpleMap("vdcId", vdcId);
		params.put("gmtModify", new Date());
		params.put("menderId", userId);
		return this.execute(sql, params) > 0;
	}

	public int count(List<Param> params, String type) {
		String sql = "select count(1) from network a,cloud_vendor b where a.is_deleted = 0 and a.vendor_id = b.id";
		if (!StringUtils.isEmpty(type)) {
			sql += " and b.type = '" + type + "'";
		}
		sql = QueryBuilder.buildRaw(sql, params, null, "a");
		Map<String, Object> param = QueryBuilder.getParam(params);
		return this.countQuery(sql, param).intValue();
	}

	public List<Network> listByVid(Long vendorId, Long tenantId) {
		String sql = "select a.* from network a where a.is_deleted = 0 and a.vendor_id = :vendorId ";
		Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
		if (0 != tenantId) {
			sql += "and a.id in(select b.network_id from tenant_network b where b.tenant_id =" + tenantId + ")";
		}
		return this.list(Network.class, sql, params);
	}

	public List<Network> listExternalByVid(Long vendorId, Long tenantId) {
		String sql = "select a.* from network a where a.is_deleted = 0 and a.is_router_external = 1 and a.vendor_id =:vendorId";
		Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
		if (null != tenantId && 0L != tenantId) {
			sql += " and a.id in(select b.network_id from tenant_network b where b.tenant_id =" + tenantId + ")";
		}
		return this.list(Network.class, sql, params);
	}

	public int count(List<Param> params, Long tenantId, Long projectId) {
		String sql = null;
		if (null != tenantId) {
			sql = "select count(a.id) from network a left join cloud_vendor v on a.vendor_id = v.id where a.is_deleted = 0 and a.id in(select t.network_id from tenant_network t where t.tenant_id = "
					+ tenantId + " and t.project_id = " + projectId + ")";
		} else {
			sql = "select count(a.id) from network 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 List<Network> list(int page, int rows, List<Param> params, Map<String, String> sorter, Long tenantId,
			Long projectId) {
		String sql = null;
		if (null != tenantId) {
			sql = "select a.*,v.name vendor_name,v.type vendor_type from network a "
					+ " left join cloud_vendor v on a.vendor_id = v.id "
					+ " where a.is_deleted = 0 and a.id in(select t.network_id from tenant_network t where t.tenant_id ="
					+ tenantId + " and t.project_id = " + projectId + ")";
		} else {
			sql = "select a.* from network a 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(Network.class, sql, paramMap);
	}

	public boolean exists(String name, Long vdcId, String type) {
		String sql = "select a.* from network a where a.is_deleted = 0 and a.vdc_id = :vdcId and a.name = :name and a.type = :type";
		Map<String, Object> params = MapTools.simpleMap("vdcId", vdcId);
		params.put("name", name);
		params.put("type", type);
		List<Network> networks = this.list(Network.class, sql, params);
		if (networks.isEmpty()) {
			return false;
		}
		return true;
	}

	public boolean inUseByTenants(Long vendorId) {
		String sql = "select count(1) from network a where a.is_deleted = 0 and a.vendor_id = :vendorId and a.id in (select t.network_id from tenant_network t)";
		Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
		return this.countQuery(sql, params).intValue() > 0;
	}

	public Network getByNameAndType(String name, Long vdcId, String type) {
		String sql = "select a.* from network a where a.is_deleted = 0 and a.vdc_id = :vdcId and a.name = :name and a.type = :type";
		Map<String, Object> params = MapTools.simpleMap("vdcId", vdcId);
		params.put("name", name);
		params.put("type", type);
		List<Network> networks = this.list(Network.class, sql, params);
		if (networks.isEmpty()) {
			return null;
		}
		return networks.get(0);
	}

	public Network getByName(String name, Long vendorId) {
		String sql = "select a.* from network a where a.is_deleted = 0 and a.vendor_id = :vendorId and a.name = :name";
		Map<String, Object> params = MapTools.simpleMap("vendorId", vendorId);
		params.put("name", name);
		List<Network> networks = this.list(Network.class, sql, params);
		if (networks.isEmpty()) {
			return null;
		}
		return networks.get(0);
	}

	public List<Network> listBySwitcher(Long switcherId) {
		String sql = "select a.* from network a where a.is_deleted = 0 and a.switcher_id = :switcherId";
		Map<String, Object> params = MapTools.simpleMap("switcherId", switcherId);
		return this.list(Network.class, sql, params);
	}

	public List<Network> listByVid(Long vendorId, String regionId) {
		String sql = "select a.*,b.name vdc_name from network a left join vdc b on a.vdc_id = b.id where a.is_deleted = 0 and a.vendor_id =:vendorId ";
		Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
		return this.list(Network.class, sql, params);
	}

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

	public List<Network> listOpaqueNetworks(String opaqueNetworkType, Long hostId) {
		String sql = "select a.* from network a left join network_host b on b.network_id = a.id and b.category = 'PM' where a.is_deleted = 0 and a.opaque_network_type = :opaqueNetworkType and b.vhost_id = :hostId";
		Map<String, Object> params = MapTools.simpleMap("opaqueNetworkType", opaqueNetworkType);
		params.put("hostId", hostId);
		return this.list(Network.class, sql, params);
	}

	public Network getNsxNetwork(String name, Long vendorId) {
		String sql = "select a.* from network a where a.is_deleted = 0 and a.name = :name and a.vendor_id = :vendorId";
		Map<String, Object> params = MapTools.simpleMap(Common.NAME, name);
		params.put(Common.VENDORID, vendorId);
		List<Network> list = this.list(Network.class, sql, params);
		if (list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}

	public List<Network> listByNetworkIds(List<Long> networkIds) {
		String sql = "select a.* from network a where a.is_deleted = 0 and a.id in (:networkIds)";
		Map<String, Object> params = MapTools.simpleMap("networkIds", networkIds);
		return this.list(Network.class, sql, params);
	}

}
