package com.bocloud.ims.repository.resource;

import com.alibaba.fastjson.JSON;
import com.bocloud.common.model.Pager;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.utils.Common;
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.Resource;
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;
import java.util.stream.Collectors;

/**
 * 资源抽血数据访问
 *
 * @author wangyu
 * @version 1.0
 * @since 2020年5月15日
 */
@Repository("resourceRepository")
public class ResourceRepository extends BasicGenericDao<Resource, Long> {

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

	public List<Resource> list(int page, int rows, List<Param> params, Map<String, String> sorter) {
		Map<String, Object> paramMap = QueryBuilder.getParam(params);
		String sql = "select res.*,v.name vendor_name,t.name tenant_name,g.name group_name, " +
				" u.name owner_name " +
				" from resource res " +
				" left join cloud_vendor v on res.vendor_id = v.id" +
				" left join tenant t on res.tenant_id = t.id " +
				" left join pool_group g on res.group_id = g.id " +
				" left join users u on res.owner_id = u.id " +
				" where res.is_deleted = 0";
		sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, params, sorter), "res");
		return this.list(Resource.class, sql, paramMap);
	}

	public List<Resource> list(int page, int rows, List<Param> params, Map<String, String> sorter, Long tenantId,
							   Long userId) {
		Map<String, Object> paramMap = QueryBuilder.getParam(params);
		String sql = "select * from resource r where r.is_deleted = 0 and r.target in ("
				+ "select a.id from cloud_server a,object_relation b where a.is_deleted = 0 and a.id = b.res_id and b.category = 'Computer'";
		if (null != userId) {
			sql += " and b.catalog = 'User' and b.target = " + userId;
		}
		if (null != tenantId) {
			sql += " and a.tenant_id = " + tenantId;
		}
		sql += ")";
		sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, params, sorter), "r");
		return this.list(Resource.class, sql, paramMap);
	}

	public int count(List<Param> params, Long tenantId, Long userId) {
		Map<String, Object> param = QueryBuilder.getParam(params);
		String sql = "select count(1) from resource r where r.is_deleted = 0 and r.target in ("
				+ "select a.id from cloud_server a,object_relation b where a.is_deleted = 0 and a.id = b.res_id and b.category = 'Computer'";
		if (null != userId) {
			sql += " and b.catalog = 'User' and b.target = " + userId;
		}
		if (null != tenantId) {
			sql += " and a.tenant_id = " + tenantId;
		}
		sql += ")";
		sql = QueryBuilder.buildRaw(sql, params, null, "r");
		return this.countQuery(sql, param).intValue();
	}

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

	public Resource query(Long id) {

		String sql = " select res.*, v.name vendor_name,t.name tenant_name,g.name group_name, " +
				" u.name owner_name " +
				" from resource res " +
				" left join cloud_vendor v on res.vendor_id = v.id" +
				" left join tenant t on res.tenant_id = t.id " +
				" left join pool_group g on res.group_id = g.id " +
				" left join users u on res.owner_id = u.id " +
				" where res.is_deleted = 0 and res.id = :id ";
		Map<String, Object> params = MapTools.simpleMap(Common.ID, id);
		List<Resource> list = this.list(Resource.class, sql, params);
		if (list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}

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

	public Resource query(String category, String catalog, Long target) {
		String sql = "select * from resource where is_deleted = 0 and category = :category and catalog = :catalog and target = :target";
		Map<String, Object> params = MapTools.simpleMap("category", category);
		params.put("catalog", catalog);
		params.put("target", target);
		List<Resource> list = this.list(Resource.class, sql, params);
		if (list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}

	public Resource query(String category, String catalog, Long target, Long vendorId) {
		String sql = "select * from resource where is_deleted = 0"
				+ " and category = :category and catalog = :catalog and target = :target and vendor_id = :vendorId";
		Map<String, Object> params = MapTools.simpleMap("category", category);
		params.put("catalog", catalog);
		params.put("target", target);
		params.put(Common.VENDORID, vendorId);
		List<Resource> list = this.list(Resource.class, sql, params);
		if (list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}

	public List<Resource> listByVid(Long vendorId) {
		String sql = "select * from resource where is_deleted = 0 and vendor_id = :vendorId";
		Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
		return this.list(Resource.class, sql, params);
	}

	public Resource getByHost(String ip, String category) {
		String sql = "select * from resource where is_deleted = 0 and ip = :ip and category = :category";
		Map<String, Object> params = MapTools.simpleMap("ip", ip);
		params.put("category", category);
		List<Resource> list = this.list(Resource.class, sql, params);
		if (list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}

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

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

	public List<Resource> listBySource(Long source, String category, String env) {
		String sql = "select a.* from resource a ,resource_relation b where a.is_deleted = 0 and a.id = b.target and a.category = :category and b.source = :source";
		Map<String, Object> params = MapTools.simpleMap("source", source);
		params.put("category", category);
		if (!StringUtils.isEmpty(env)) {
			sql = sql + " and a.env = :env";
			params.put("env", env);
		}
		return this.list(Resource.class, sql, params);
	}

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

	public boolean updateAccount(Resource resource) {
		String sql = "update resource set username = :username, password = :password  where id=:id";
		Map<String, Object> params = MapTools.simpleMap("id", resource.getId());
		params.put("username", resource.getUsername());
		params.put("password", resource.getPassword());
		return this.execute(sql, params) > 0;
	}

	public Resource queryByTargetId(Long targetId) {
		String sql = "select * from resource where is_deleted = 0 and target = :targetId and category = 'Computer' and catalog = 'LOGICAL'";
		Map<String, Object> params = MapTools.simpleMap("targetId", targetId);
		List<Resource> list = this.list(Resource.class, sql, params);
		if (list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}

	public boolean tenantCheck(Long tenantId, Long creatorId) {
		String sql = "select count(1) from resource 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 != creatorId && 0L != creatorId) {
			sql += " and a.creator_id = :creatorId";
			paramMap.put("creatorId", creatorId);
		}
		return this.countQuery(sql, paramMap).intValue() > 0;
	}

	public List<Resource> queryByGroupId(Long poolGroupId) {
		String sql = "select * from resource where group_id =:poolGroupId and is_deleted = 0";
		Map<String, Object> params = MapTools.simpleMap("poolGroupId", poolGroupId);
		List<Resource> list = this.list(Resource.class, sql, params);
		return list;
	}

	public boolean migrate(Long resourceId, Long groupId, String groupIds, RequestContext context) {
		Long userId = context.getTarget();
		String sql = "update resource set group_id = :groupId, group_ids = :groupIds, mender_id = :userId where id=:resourceId ";
		Map<String, Object> params = MapTools.simpleMap("resourceId", resourceId);
		params.put("groupId", groupId);
		params.put("groupIds", groupIds);
		params.put("userId", userId);
		return this.execute(sql, params) > 0;
	}

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

	public Resource query(Long target, String catalog) {
		String sql = "select a.id from resource a where is_deleted = 0 and catalog = :catalog and target = :target ";
		Map<String, Object> params = MapTools.simpleMap("target", target);
		params.put("catalog", catalog);
		List<Resource> list = this.list(Resource.class, sql, params);
		if (list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}

	public boolean tenantCheck(Long tenantId, Long projectId, Long creatorId) throws Exception {
		String sql = "select count(1) from resource 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 List<Resource> listByGroupId(Long groupId, Long vendorId, String resourceIp, boolean flag) {
		String sql = " select res.*, t.name tenant_name" +
				" from resource res " +
				" left join tenant t on res.tenant_id = t.id " +
				" where res.vendor_id = :vendorId  and res.is_deleted = 0 ";
		Map<String, Object> paramMap = Maps.newHashMap();
		paramMap.put("vendorId", vendorId);
		if (resourceIp != null) {
			sql += " and private_ips like '%" + resourceIp + "%' ";
		}
		List<Resource> resources = this.list(Resource.class, sql, paramMap);
		List<Resource> contains = resources.stream().filter(
				resource -> resource.getGroupIds() != null
						&& JSON.parseArray(resource.getGroupIds(), Long.class).contains(groupId)
						&& JSON.parseArray(resource.getGroupIds(), Long.class).size() > 0)
				.collect(Collectors.toList());
		resources.removeAll(contains);
		return flag ? resources : contains;
	}

	public boolean recycle(Long id, Long userId) {
		String sql = "update resource set is_accurated = 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 restore(Long id, Long userId) {
		String sql = "update resource set is_accurated = false,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 Resource getByUuid(String uuid) {
		String sql = "select a.* from resource a where a.is_deleted = 0 and a.uuid = :uuid";
		Map<String, Object> params = MapTools.simpleMap("uuid", uuid);
		List<Resource> list = this.list(Resource.class, sql, params);
		if (list.isEmpty()) {
			return null;
		}
		return list.get(0);
	}

	/**
	 * 获取堡垒机中资产的ip和负责人id的对应关系
	 *
	 * @author sxp
	 * @since 2022/11/24
	 */
	public List<Resource> listJumpServerResource() {
		String sql = "select a.private_ips,d.id " +
				" from resource a, " +
				"      jumpserver_relation b, " +
				"      jumpserver_user c, " +
				"      users d " +
				"where a.id = b.src_id " +
				"and b.type='DEVICE__USER' " +
				"and b.dst_id = c.id " +
				"and c.`name` = d.`name` " +
				"and a.is_deleted = 0  " +
				"and c.is_deleted = 0  " +
				"and d.is_deleted = 0  " +
				"and a.vendor_id in (select t.id from cloud_vendor t where t.is_deleted=0 and t.type = 'JUMPSERVER') ";
		Map<String, Object> params = new HashMap<>(0);
		List<Resource> list = this.list(Resource.class, sql, params);
		return list;
	}
}
