package com.bocloud.ims.repository.resource;

import com.bocloud.common.model.Pager;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.Sign;
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.Ip;
import com.bocloud.ims.entity.resource.Ip.IpStatus;
import com.bocloud.orm.OrmBasicDaoImpl;
import com.bocloud.orm.OrmGenericDaoImpl;
import com.google.common.collect.Maps;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;

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

/**
 * @author wangyu
 * @version 5.1.0
 * @description IP数据访问
 * @date: 2020-11-30
 */
@Repository("ipRepository")
public class IpRepository extends OrmGenericDaoImpl<Ip, Long> {

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

    public List<Ip> list(int page, int rows, List<Param> params, Map<String, String> sorter) {
        String sql = "select a.*,b.name vendor_name,n.name network_name,p.name pool_name from ip a LEFT JOIN ip_pool p ON p.id = a.pool_id left join cloud_vendor b on a.vendor_id=b.id left join network n on n.id = a.network_id where 1 = 1 ";

        List<Param> paramList = params;
        if (!ListTool.isEmpty(params)) {
            for (Param param : params) {
                Sign sign = param.getSign();
                if ("like".equals(sign.getSign())) {
                    Map<String, Object> map = param.getParam();
                    for (String key : map.keySet()) {
                        String value = String.valueOf(map.get(key));
                        switch (key) {
                            case "poolName":
                                sql += "and p.name LIKE \'%" + value + "%\'";
                                map.remove(key);
//								paramList.remove(param);
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
        }
        Map<String, Object> paramMap = QueryBuilder.getParam(params);
        sql = QueryBuilder.buildRaw(sql, new Pager(page, rows, paramList, sorter), "a");
        return this.list(Ip.class, sql, paramMap);
    }

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

    public Ip query(Long id) {
        String sql = "select a.*,b.name vendor_name from ip a left join cloud_vendor b on a.vendor_id=b.id where a.id = :id";
        Map<String, Object> params = MapTools.simpleMap(Common.ID, id);
        List<Ip> list = this.list(Ip.class, sql, params);
        return ListTool.isEmpty(list) ? null : list.get(0);
    }


    /**
     * 检验IP是否在IP地址池中
     *
     * @param poolId IP地址池的唯一标识
     * @param ip IP地址
     * @author sxp
     * @since 2023/10/10
     */
    public boolean checkIpInPool(Long poolId, String ip) {
        String sql = "select a.* from ip a where a.pool_id = :poolId and a.ip = :ip ";
        Map<String, Object> params = MapTools.simpleMap("poolId", poolId);
        params.put("ip", ip);
        List<Ip> list = this.list(Ip.class, sql, params);
        if (list == null || list.isEmpty()) {
            return false;
        }
        return true;
    }

    public Ip checkIp(Long poolId, String ip) {
        String sql = "select a.* from ip a where a.pool_id = :poolId and a.ip = :ip and a.status != 'free' ";
        Map<String, Object> params = MapTools.simpleMap("poolId", poolId);
        params.put("ip", ip);
        List<Ip> list = this.list(Ip.class, sql, params);
        return ListTool.isEmpty(list) ? null : list.get(0);
    }

    public Boolean delete(Long id) {
        String sql = "delete from ip where id = :id";
        Map<String, Object> params = MapTools.simpleMap(Common.ID, id);
        return this.execute(sql, params) > 0;
    }

    public Boolean deleteByVid(Long vendorId) {
        String sql = "delete from ip where vendor_id = :vendorId";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        return this.execute(sql, params) > 0;
    }

    public Boolean deleteByNetworkId(Long networkId) {
        String sql = "delete from ip where network_id = :networkId";
        Map<String, Object> params = MapTools.simpleMap("networkId", networkId);
        return this.execute(sql, params) > 0;
    }

    public Ip checkExist(String ip, Long subnetId, Long vendorId) {
        String sql = "select * from ip where ip = :ip ";
        Map<String, Object> params = MapTools.simpleMap("ip", ip);
        if (null != subnetId && 0L != subnetId) {
            sql += " and subnet_id = " + subnetId;
        }
		if (null != vendorId && 0L != vendorId) {
			sql += " and vendor_id = :vendorId ";
			params.put(Common.VENDORID, vendorId);
		}
        List<Ip> list = this.list(Ip.class, sql, params);
        return ListTool.isEmpty(list) ? null : list.get(0);
    }

    public boolean batchUpdate(List<Ip> iplist) {
        Integer batchSize = iplist.size();
        return this.batchUpdate(iplist, batchSize);
    }

    public boolean batchCreate(List<Ip> iplist) {
        return this.batchSave(iplist, 1000);
    }

    public List<Ip> listByPool(Long poolId) {
        String sql = "select * from ip where pool_id = :poolId";
        Map<String, Object> params = MapTools.simpleMap("poolId", poolId);
        return this.list(Ip.class, sql, params);
    }


    public List<Ip> listStatusByPool(Long poolId) {
        String sql = "select * from ip where pool_id = :poolId and status= 'free'";
        Map<String, Object> params = MapTools.simpleMap("poolId", poolId);
        return this.list(Ip.class, sql, params);
    }

    public Boolean updateStatusIp(List<String> ips) {
        String sql = "update ip set status = 'preempt' where ip in (:ips)";
        Map<String, Object> params = MapTools.simpleMap("ips", ips);
        return this.execute(sql, params) > 0;
    }

    public List<Ip> listIpsByPool(Long poolId, List<String> ips) {
        String sql = "select a.* from ip a where a.pool_id = :poolId and a.ip in (:ips) ";
        Map<String, Object> params = MapTools.simpleMap("poolId", poolId);
        params.put("ips", ips);
        return this.list(Ip.class, sql, params);
    }

    public List<Ip> listByPool(Long poolId, IpStatus status) {
        String sql = "select * from ip where pool_id = :poolId and status = :status";
        Map<String, Object> params = MapTools.simpleMap("poolId", poolId);
        params.put("status", status.name());
        return this.list(Ip.class, sql, params);
    }

	public boolean delete(Long target, String catalog, Long vendorId) {
		// 5.6版本IP池中的IP是不允许被删除掉的 #PBSM-13169 bug
		// 初步怀疑是调用delete方法将IP删除导致的，因为调用的地方有点多，版本今天要发布，所以直接修改源头，后续该部分逻辑需要移到相关业务层
		String sql = "select * from ip where target = :target and catalog = :catalog and vendor_id = :vendorId";
		Map<String, Object> params = MapTools.simpleMap("target", target);
		params.put("catalog", catalog);
		params.put(Common.VENDORID, vendorId);
		List<Ip> list = this.list(Ip.class, sql, params);
		if (ListTool.isEmpty(list)) {
			return true;
		}
		for (Ip ip : list) {
			if (null != ip.getPoolId() && ip.getPoolId() > 0) {
				this.makeFreeById(ip.getId());
			} else {
				sql = "delete from ip where target = :target and catalog = :catalog and vendor_id = :vendorId";
				this.execute(sql, params);
			}
		}
		return true;
	}

    public Ip checkExist(String ip, Long target, String catalog, Long vendorId) {
        String sql = "select * from ip where ip = :ip and target = :target and catalog = :catalog and vendor_id = :vendorId";
        Map<String, Object> params = MapTools.simpleMap("ip", ip);
        params.put("target", target);
        params.put("catalog", catalog);
        params.put(Common.VENDORID, vendorId);
        List<Ip> list = this.list(Ip.class, sql, params);
        return ListTool.isEmpty(list) ? null : list.get(0);
    }

    public boolean delete(String ip, Long subnetId, Long vendorId) {
        String sql = "delete from ip where ip = :ip and subnet_id = :subnetId and vendor_id = :vendorId";
        Map<String, Object> params = MapTools.simpleMap("ip", ip);
        params.put("subnetId", subnetId);
        params.put(Common.VENDORID, vendorId);
        return this.execute(sql, params) > 0;
    }

    public int count(Long subnetId, Long vendorId) {
        String sql = "select count(1) from ip where subnet_id = :subnetId and vendor_id = :vendorId";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        params.put("subnetId", subnetId);
        return this.countQuery(sql, params).intValue();
    }

	public boolean delete(Long target, String catalog) {
		// 5.6版本IP池中的IP是不允许被删除掉的 #PBSM-13169 bug
		// 初步怀疑是调用delete方法将IP删除导致的，因为调用的地方太多了，版本今天要发布，所以直接修改源头，后续该部分逻辑需要移到相关业务层
		String sql = "select * from ip where target = :target and catalog = :catalog ";
		Map<String, Object> params = MapTools.simpleMap("target", target);
		params.put("catalog", catalog);
		List<Ip> list = this.list(Ip.class, sql, params);
		if (ListTool.isEmpty(list)) {
			return true;
		}
		for (Ip ip : list) {
			if (null != ip.getPoolId() && ip.getPoolId() > 0) {
				this.makeFreeById(ip.getId());
			} else {
				sql = "delete from ip where target = :target and catalog = :catalog";
				this.execute(sql, params);
			}
		}
		return true;
	}

    public List<Ip> listByVendor(Long vendorId) {
        String sql = "select * from ip where vendor_id = :vendorId";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        return this.list(Ip.class, sql, params);
    }

    public List<Ip> listAll() {
        String sql = "select * from ip ";
        return this.list(Ip.class, sql);
    }
    
    public List<Ip> listNotInPools() {
        String sql = "select a.* from ip a where a.pool_id is null;";
        return this.list(Ip.class, sql);
    }

    public List<Ip> listByVcIpPoolIps(Long vendorId) {
        String sql = "select a.* from ip a left join ip_pool b on b.id = a.pool_id where a.vendor_id = :vendorId and (b.router_port_id is null or a.segment_id is null)";
        Map<String, Object> params = MapTools.simpleMap(Common.VENDORID, vendorId);
        return this.list(Ip.class, sql, params);
    }

    public boolean deleteByVendor(String catalog, Long vendorId, List<String> existIps) {
        String sql = "delete from ip where catalog = :catalog and vendor_id = :vendorId ";
        Map<String, Object> params = MapTools.simpleMap("catalog", catalog);
        params.put(Common.VENDORID, vendorId);
        if (!ListTool.isEmpty(existIps)) {
            sql += "and ip not in (:existIps)";
            params.put("existIps", existIps);
        }
        return this.execute(sql, params) > 0;
    }

    public boolean deleteNullIp(String catalog, Long vendorId) {
        String sql = "delete from ip where catalog = :catalog and vendor_id = :vendorId and ip is null";
        Map<String, Object> params = MapTools.simpleMap("catalog", catalog);
        params.put(Common.VENDORID, vendorId);
        return this.execute(sql, params) > 0;
    }

    public boolean deleteByPortId(Long portId) {
        String sql = "delete a from ip a join port_fixedip b on a.ip = b.ip_address and a.subnet_id = b.subnet_id "
                + "where b.port_id = :portId";
        Map<String, Object> params = Maps.newHashMap();
        params.put("portId", portId);
        return this.execute(sql, params) > 0;
    }

    public List<Ip> alarmIps(Long vendorId) {
        String sql = "select a.ip from ip a left join cloud_vendor b on b.id = a.vendor_id where b.is_alarm = 1 ";
        Map<String, Object> params = Maps.newHashMap();
        if (null != vendorId && 0L != vendorId) {
            sql += " and a.vendor_id = :vendorId";
            params.put(Common.VENDORID, vendorId);
        }
        return this.list(Ip.class, sql, params);
    }

    public List<Ip> listByRouterPortId(Long routerPortId) {
        String sql = "select a.* from ip a left join ip_pool b on b.id = a.pool_id where b.router_port_id = :routerPortId";
        Map<String, Object> params = MapTools.simpleMap("routerPortId", routerPortId);
        return this.list(Ip.class, sql, params);
    }

    public boolean delete(String ip, Long poolId) {
        String sql = "delete from ip where ip = :ip and pool_id = :poolId";
        Map<String, Object> params = MapTools.simpleMap("ip", ip);
        params.put("poolId", poolId);
        return this.execute(sql, params) > 0;
    }

    public List<Ip> listLockedIps() {
        String sql = "select a.* from ip a where a.status != 'free' ";
        return this.list(Ip.class, sql, new HashMap<>(8));
    }

    public Boolean deleteBySubnetId(Long subnetId, Long vendorId) {
        String sql = "delete from ip where subnet_id = :subnetId and vendor_id = :vendorId";
        Map<String, Object> params = MapTools.simpleMap("subnetId", subnetId);
        params.put(Common.VENDORID, vendorId);
        return this.execute(sql, params) > 0;
    }

    public List<Ip> listByStatus(List<String> statusList, Long poolId) {
        String sql = "select * from ip where 1 = 1 ";
        Map<String, Object> paramMap = new HashMap<>(8);
        if (!ListTool.isEmpty(statusList)) {
            sql += " and status in (:statusList)";
            paramMap.put("statusList", statusList);
        }
        if (null != poolId && 0L != poolId) {
            sql += " and pool_id = :poolId";
            paramMap.put("poolId", poolId);
        }
        return this.list(Ip.class, sql, paramMap);
    }

    public boolean makeFree(String catalog, List<String> existIps, Long vendorId) {
        String sql = "update ip set status = '" + IpStatus.free.name()
                + "',catalog = null where vendor_id = :vendorId and catalog = :catalog and status != '"
                + IpStatus.lock.name() + "'";
        Map<String, Object> params = MapTools.simpleMap("catalog", catalog);
        params.put("vendorId", vendorId);
        if (!ListTool.isEmpty(existIps)) {
            sql += " and ip not in (:existIps)";
            params.put("existIps", existIps);
        }
        return this.execute(sql, params) > 0;
    }

    public boolean makeFreeById(Long id) {
        String sql = "update ip set status = '" + IpStatus.free.name()
                + "',catalog = null,target = null,remark = null where id = :id";
        Map<String, Object> params = MapTools.simpleMap(Common.ID, id);
        return this.execute(sql, params) > 0;
    }

    public boolean makeFreeByTarget(Long target, String catalog, Long vendorId) {
        String sql = "update ip set status = '" + IpStatus.free.name()
                + "',target = null,catalog = null where vendor_id = :vendorId and target = :target and catalog = :catalog";
        Map<String, Object> params = MapTools.simpleMap("target", target);
        params.put("catalog", catalog);
        params.put("vendorId", vendorId);
        return this.execute(sql, params) > 0;
    }

    public Boolean deleteByPoolId(Long poolId) {
        String sql = "delete from ip where pool_id = :poolId";
        Map<String, Object> params = MapTools.simpleMap("poolId", poolId);
        return this.execute(sql, params) > 0;
    }

}
