package com.bocloud.ims.repository.resource;

import com.bocloud.common.utils.MapTools;
import com.bocloud.database.utils.PageHelper;
import com.bocloud.ims.entity.resource.StorageFCPort;
import com.bocloud.ims.entity.resource.StorageGroup;
import com.bocloud.ims.entity.resource.StorageGroupMember;
import com.bocloud.ims.entity.resource.StorageHost;
import com.bocloud.ims.entity.resource.Volume;
import com.bocloud.ims.repository.resource.common.EnhancedBaseRepository;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Repository("storageGroupMemberRepository")
public class StorageGroupMemberRepository extends EnhancedBaseRepository<StorageGroupMember, Long> {

	public void remove(long id) {
		String sql = "delete from storage_group_member where id = :id";
		Map<String, Object> params = MapTools.simpleMap("id", id);
		this.update(sql, params);
	}

	public void remove(long groupId, long memberId) {
		String sql = "delete from storage_group_member where group_id = :groupId and member_id = :memberId ";
		Map<String, Object> params = MapTools.simpleMap("groupId", groupId);
		params.put("memberId", memberId);
		this.update(sql, params);

	}

	public void removeByGroup(long groupId) {
		String sql = "delete from storage_group_member where group_id = :groupId";
		Map<String, Object> params = MapTools.simpleMap("groupId", groupId);
		this.update(sql, params);
	}

	public void removeByMember(long memberId, String groupType) {
		String sql = "delete from storage_group_member where member_id = :memberId and group_id in "
				+ "(select id from storage_group where is_deleted = 0 and type = :groupType)";
		Map<String, Object> params = MapTools.simpleMap("memberId", memberId);
		params.put("groupType", groupType);
		this.update(sql, params);
	}

	public List<StorageGroupMember> listByGroup(long groupId) {
		String sql = "select * from storage_group_member where group_id = :groupId";
		Map<String, Object> params = MapTools.simpleMap("groupId", groupId);
		return this.list(StorageGroupMember.class, sql, params);
	}

	public List<StorageGroupMember> listByMember(long memberId, String groupType) {
		String sql = "select * from storage_group_member where member_id = :memberId and group_id in "
				+ "(select id from storage_group where is_deleted = 0 and type = :groupType)";
		Map<String, Object> params = MapTools.simpleMap("memberId", memberId);
		params.put("groupType", groupType);
		return this.list(StorageGroupMember.class, sql, params);
	}

	public List<StorageGroup> listGroupByMember(long memberId, String groupType) {
		String sql = "select b.* from storage_group_member a left join storage_group b on a.group_id = b.id where a.member_id = :memberId and b.type = :groupType ";
		Map<String, Object> params = MapTools.simpleMap("memberId", memberId);
		params.put("groupType", groupType);
		List<Object> objects = this.queryForList(sql, params, StorageGroup.class);
		List<StorageGroup> groups = new ArrayList<>();
		objects.forEach(o -> groups.add((StorageGroup) o));
		return groups;
	}

	public StorageGroupMember getByGroupAndMember(long groupId, long memberId) {
		String sql = "select * from storage_group_member where group_id = :groupId and member_id = :memberId";
		Map<String, Object> params = MapTools.simpleMap("groupId", groupId);
		params.put("memberId", memberId);
		List<StorageGroupMember> list = this.list(StorageGroupMember.class, sql, params);
		return list == null || list.size() == 0 ? null : list.get(0);
	}

	public List<Volume> listVolumeByGroup(int page, int rows, long groupId, Map<String, Object> params) {
		String sql = " select a.*, c.name as pool_name "
				+ " from volume a left join volume_pool c on a.pool_id = c.id "
				+ " where a.is_deleted = 0 and a.id in (select b.member_id from storage_group_member b where b.group_id = :groupId) ";
		Map<String, Object> sqlParams = MapTools.simpleMap("groupId", groupId);
		if (params.containsKey("name")) {
			sql += " and a.name like :name";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		if (params.containsKey("poolId")) {
			sql += " and a.pool_id = :poolId";
			sqlParams.put("poolId", params.get("poolId"));
		}
		sql += PageHelper.buildPageSql(page, rows);
		List<Object> objects = this.queryForList(sql, sqlParams, Volume.class);
		List<Volume> volumes = new ArrayList<>();
		for (Object object : objects) {
			volumes.add((Volume) object);
		}
		return volumes;
	}

	public int countVolumeByGroup(long groupId, Map<String, Object> params) {
		String sql = " select count(1) from volume a "
				+ " where a.is_deleted = 0 and a.id in (select b.member_id from storage_group_member b where b.group_id = :groupId) ";
		Map<String, Object> sqlParams = MapTools.simpleMap("groupId", groupId);
		if (params.containsKey("name")) {
			sql += " and a.name like :name";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		if (params.containsKey("poolId")) {
			sql += " and a.pool_id = :poolId";
			sqlParams.put("poolId", params.get("poolId"));
		}
		return this.countQuery(sql, sqlParams).intValue();
	}

	public List<StorageHost> listHostByGroup(int page, int rows, long groupId, Map<String, Object> params){
		String sql = " select a.* from storage_host a "
				+ " where a.is_deleted = 0 and a.id in (select b.member_id from storage_group_member b where b.group_id = :groupId) ";
		Map<String, Object> sqlParams = MapTools.simpleMap("groupId", groupId);
		if (params.containsKey("name")) {
			sql += " and a.name like :name";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		sql += PageHelper.buildPageSql(page, rows);
		List<Object> objects = this.queryForList(sql, sqlParams, StorageHost.class);
		List<StorageHost> hosts = new ArrayList<>();
		for (Object object : objects) {
			hosts.add((StorageHost) object);
		}
		return hosts;
	}

	public int countHostByGroup(long groupId, Map<String, Object> params) {
		String sql = " select count(1) from storage_host a "
				+ " where a.is_deleted = 0 and a.id in (select b.member_id from storage_group_member b where b.group_id = :groupId) ";
		Map<String, Object> sqlParams = MapTools.simpleMap("groupId", groupId);
		if (params.containsKey("name")) {
			sql += " and a.name like :name";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		return this.countQuery(sql, sqlParams).intValue();
	}

	public List<StorageFCPort> listFcPortByGroup(int page, int rows, long groupId, Map<String, Object> params)
			throws Exception {
		String sql = " select a.* from storage_fc_port a "
				+ " where a.is_deleted = 0 and a.id in (select b.member_id from storage_group_member b where b.group_id = :groupId) ";
		Map<String, Object> sqlParams = MapTools.simpleMap("groupId", groupId);
		if (params.containsKey("name")) {
			sql += " and a.name like :name";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		sql += PageHelper.buildPageSql(page, rows);
		List<Object> objects = this.queryForList(sql, sqlParams, StorageFCPort.class);
		List<StorageFCPort> fcPorts = new ArrayList<>();
		for (Object object : objects) {
			fcPorts.add((StorageFCPort) object);
		}
		return fcPorts;
	}

	public int countFcPortByGroup(long groupId, Map<String, Object> params) {
		String sql = " select count(1) from storage_fc_port a "
				+ " where a.is_deleted = 0 and a.id in (select b.member_id from storage_group_member b where b.group_id = :groupId) ";
		Map<String, Object> sqlParams = MapTools.simpleMap("groupId", groupId);
		if (params.containsKey("name")) {
			sql += " and a.name like :name";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		return this.countQuery(sql, sqlParams).intValue();
	}

	public List<Volume> listVolumeNotInGroupId(int page, int rows, long groupId, Map<String, Object> params,
			Map<String, String> sorter) {
		String sql = "select a.*, b.name as pool_name from volume a "
				+ "left join volume_pool b on a.pool_id = b.id "
				+ "where a.is_deleted = 0 "
				+ "and a.id not in (select member_id from storage_group_member where group_id = :groupId ) "
				+ "and a.storage_id = (select storage_id from storage_group where id = :groupId) ";
		Map<String, Object> sqlParams = new HashMap<>(8);
		sqlParams.put("groupId", groupId);
		if (params.containsKey("name")) {
			sql += " and a.name like :name";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		if (params.containsKey("poolId")) {
			sql += " and a.pool_id = :poolId";
			sqlParams.put("poolId", params.get("poolId"));
		}
		sql += PageHelper.buildPageSql(page, rows);
		return this.queryForList(sql, sqlParams, Volume.class).stream().map(o -> (Volume) o)
				.collect(Collectors.toList());
	}

	public int countVolumeNotInGroupId(long groupId, Map<String, Object> params) {
		String sql = "select count(1) from volume a " + "left join volume_pool b on a.pool_id = b.id "
				+ "where a.is_deleted = 0 "
				+ "and a.id not in (select member_id from storage_group_member where group_id = :groupId ) "
				+ "and a.storage_id = (select storage_id from storage_group where id = :groupId) ";
		Map<String, Object> sqlParams = new HashMap<>(8);
		sqlParams.put("groupId", groupId);
		if (params.containsKey("name")) {
			sql += " and a.name like :name";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		if (params.containsKey("poolId")) {
			sql += " and a.pool_id = :poolId";
			sqlParams.put("poolId", params.get("poolId"));
		}
		return this.countQuery(sql, sqlParams).intValue();
	}

	public List<StorageHost> listHostNotInGroupId(int page, int rows, long groupId, Map<String, Object> params,
			Map<String, String> sorter) {
		String sql = "select a.* from storage_host a where a.is_deleted = 0 "
				+ "and a.id not in (select member_id from storage_group_member where group_id = :groupId ) "
				+ "and a.storage_id = (select storage_id from storage_group where id = :groupId) ";
		Map<String, Object> sqlParams = new HashMap<>(8);
		sqlParams.put("groupId", groupId);
		if (params.containsKey("name")) {
			sql += " and a.name like :name";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		sql += PageHelper.buildPageSql(page, rows);
		return this.queryForList(sql, sqlParams, StorageHost.class).stream().map(o -> (StorageHost) o)
				.collect(Collectors.toList());
	}

	public int countHostNotInGroupId(long groupId, Map<String, Object> params) {
		String sql = "select count(1) from storage_host a where a.is_deleted = 0 "
				+ "and a.id not in (select member_id from storage_group_member where group_id = :groupId ) "
				+ "and a.storage_id = (select storage_id from storage_group where id = :groupId) ";
		Map<String, Object> sqlParams = new HashMap<>(8);
		sqlParams.put("groupId", groupId);
		if (params.containsKey("name")) {
			sql += " and a.name like :name";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		return this.countQuery(sql, sqlParams).intValue();
	}

	public List<StorageFCPort> listFcPortNotInGroupId(int page, int rows, long groupId, Map<String, Object> params,
			Map<String, String> sorter) {
		String sql = "select * from (select d.*, b.storage_id  from storage_fc_port d "
				+ "left join storage_node b on d.node_id = b.id " + "left join storage c on b.storage_id = c.id ) a "
				+ "where a.is_deleted = 0 "
				+ "and a.id not in (select member_id from storage_group_member where group_id = :groupId ) "
				+ "and a.storage_id = (select storage_id from storage_group where id = :groupId) ";
		Map<String, Object> sqlParams = new HashMap<>(8);
		sqlParams.put("groupId", groupId);
		if (params.containsKey("name")) {
			sql += " and a.name like :name";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		sql += PageHelper.buildPageSql(page, rows);
		return this.queryForList(sql, sqlParams, StorageFCPort.class).stream().map(o -> (StorageFCPort) o)
				.collect(Collectors.toList());
	}

	public int countFcPortNotInGroupId(long groupId, Map<String, Object> params) {
		String sql = "select count(1) from (select d.*, b.storage_id  from storage_fc_port d "
				+ "left join storage_node b on d.node_id = b.id " + "left join storage c on b.storage_id = c.id ) a "
				+ "where a.is_deleted = 0 "
				+ "and a.id not in (select member_id from storage_group_member where group_id = :groupId ) "
				+ "and a.storage_id = (select storage_id from storage_group where id = :groupId) ";
		Map<String, Object> sqlParams = new HashMap<>(8);
		sqlParams.put("groupId", groupId);
		if (params.containsKey("name")) {
			sql += " and a.name like :name";
			sqlParams.put("name", "%" + params.get("name") + "%");
		}
		return this.countQuery(sql, sqlParams).intValue();
	}
}
