package cn.superdesk.uniorder.service.invoice.common.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.superdesk.uniorder.common.enums.common.CommonEnabledEnum;
import cn.superdesk.uniorder.common.enums.common.CommonIsDefaultEnum;
import cn.superdesk.uniorder.common.enums.common.CommonSoftDeleteEnum;
import cn.superdesk.uniorder.common.json.AnJsonUtils;
import cn.superdesk.uniorder.common.lamda.AnLamdaUtils;
import cn.superdesk.uniorder.common.mq.redis.constants.BaseRedisConf;
import cn.superdesk.uniorder.common.mq.redis.constants.RedisKeyPrefix;
import cn.superdesk.uniorder.common.mq.redis.service.RedisService;
import cn.superdesk.uniorder.common.numerical.AnBeanUtils;
import cn.superdesk.uniorder.common.rest.response.R;
import cn.superdesk.uniorder.common.security.dto.LoginSysUser;
import cn.superdesk.uniorder.dao.entity.invoice.common.InvoiceBankInfo;
import cn.superdesk.uniorder.dao.entity.invoice.common.InvoiceBankInfoExample;
import cn.superdesk.uniorder.dao.entity.sys.SysUser;
import cn.superdesk.uniorder.dao.mapper.invoice.common.InvoiceBankInfoMapper;
import cn.superdesk.uniorder.dao.mapper.invoice.common.InvoiceBankInfoMapperEx;
import cn.superdesk.uniorder.dto.param.accounting.score.customer.AccountingOrderScoreCustomerOpDetailQueryCriteria;
import cn.superdesk.uniorder.dto.param.invoice.common.InvoiceBankInfoParam;
import cn.superdesk.uniorder.dto.param.invoice.common.InvoiceBankInfoQueryCriteria;
import cn.superdesk.uniorder.dto.vo.accounting.score.customer.AccountingOrderScoreCustomerListItemVo;
import cn.superdesk.uniorder.dto.vo.invoice.common.InvoiceBankInfoVo;
import cn.superdesk.uniorder.service.accounting.score.customer.AccountingScoreCustomerService;
import cn.superdesk.uniorder.service.invoice.common.InvoiceBankInfoService;
import cn.superdesk.uniorder.service.invoice.customer.InvoiceApplyXGoodsService;
import cn.superdesk.uniorder.service.sys.SysUserService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @Description: 重构
 * @Author: linjinyu
 * @CreateDate: 2021/7/23 下午4:03
 * @UpdateUser: linjinyu
 * @UpdateDate: 2021/7/23 下午4:03
 * @UpdateRemark: 修改内容
 * @Version: 1.0
 */
@Slf4j
@Service
public class InvoiceBankInfoServiceImpl implements InvoiceBankInfoService {

	@Autowired
	private InvoiceBankInfoMapper   invoiceBankInfoMapper;
	@Autowired
	private InvoiceBankInfoMapperEx invoiceBankInfoMapperEx;

	@Autowired
	private SysUserService sysUserService;

	@Autowired
	private AccountingScoreCustomerService accountingScoreCustomerService;

	@Autowired
	private InvoiceApplyXGoodsService invoiceApplyXGoodsService;

	@Autowired
	private InvoiceBankInfoService invoiceBankInfoService;

	@Autowired
	private RedisService redisService;

	/****************************************** extends BaseService 部分 start ******************************************/

//	@Override
//	public void addObj(InvoiceBankInfo entity) {
//		invoiceBankInfoMapper.insert(entity);
//	}
//
//	@Override
//	public void updateObj(InvoiceBankInfo entity) {
//		invoiceBankInfoMapper.updateByPrimaryKeySelective(entity);
//	}
//
//	@Override
//	public void deleteObj(Long id) {
//		invoiceBankInfoMapper.deleteByPrimaryKey(id);
//	}
//
//
//	@Override
//	public InvoiceBankInfo findById(Long id) {
//		return invoiceBankInfoMapper.selectByPrimaryKey(id);
//	}
//
//	@Override
//	public PageInfo<InvoiceBankInfo> findByPaging(Map<String, Object> conditions, Integer pageNun, Integer pageSize) {
//		return null;
//	}
//
//	@Override
//	public List<InvoiceBankInfo> findAll(Map<String, Object> queryMap) {
//		return null;
//	}

	/****************************************** extends BaseService 部分   end ******************************************/


	public int addInvoiceBankInfo(InvoiceBankInfo entity, LoginSysUser loginSysUser) {

		entity.setCreateTime(DateUtil.date());
		entity.setCreateUserId(loginSysUser.getSysUserId());

		entity.setUpdateTime(DateUtil.date());
		entity.setUpdateUserId(loginSysUser.getSysUserId());

		entity.setParam1("n");
		entity.setEnabled(CommonEnabledEnum.启用.getKey());
		entity.setIsDefault(CommonIsDefaultEnum.正常.getKey());
		entity.setDeleted(CommonSoftDeleteEnum.正常.getKey());

		return invoiceBankInfoMapper.insertSelective(entity);
	}

	public int updateInvoiceBankInfo(InvoiceBankInfo entity, LoginSysUser loginSysUser) {

		int ret = 0;

		InvoiceBankInfo originEntity = invoiceBankInfoMapper.selectByPrimaryKey(entity.getId());

		if (ObjectUtil.isNotNull(originEntity)) {

			entity.setUpdateTime(DateUtil.date());
			entity.setUpdateUserId(loginSysUser.getSysUserId());

			ret = invoiceBankInfoMapper.updateByPrimaryKeySelective(entity);

		}

		return ret;
	}


	public int opPhysicsDelete(Long id, LoginSysUser loginSysUser) {

		return invoiceBankInfoMapper.deleteByPrimaryKey(id);
	}

	public int opLogicalDelete(Long id, LoginSysUser loginSysUser) {

		int ret = 0;

		InvoiceBankInfo originEntity = invoiceBankInfoMapper.selectByPrimaryKey(id);

		if (ObjectUtil.isNotNull(originEntity)) {

			InvoiceBankInfo forUpdate = new InvoiceBankInfo();

			forUpdate.setId(id);
			forUpdate.setDeleted(CommonSoftDeleteEnum.删除.getKey());

			forUpdate.setUpdateTime(DateUtil.date());
			forUpdate.setUpdateUserId(loginSysUser.getSysUserId());

			ret = invoiceBankInfoMapper.updateByPrimaryKeySelective(forUpdate);
		}

		return ret;

	}

	@Override
	public int setNormal(Long id, LoginSysUser loginSysUser) {

		InvoiceBankInfo forUpdate = new InvoiceBankInfo();

		forUpdate.setId(id);
		forUpdate.setParam1("n");
		forUpdate.setIsDefault(CommonIsDefaultEnum.正常.getKey());

		forUpdate.setUpdateTime(DateUtil.date());
		forUpdate.setUpdateUserId(loginSysUser.getSysUserId());

		return invoiceBankInfoMapper.updateByPrimaryKeySelective(forUpdate);
	}

	public void setAllNormal() {
		invoiceBankInfoMapperEx.setAllNormal();
	}

	@Override
	public int setDefault(Long id, LoginSysUser loginSysUser) {

		// 清除默认
		setAllNormal();

		InvoiceBankInfo forUpdate = new InvoiceBankInfo();

		forUpdate.setId(id);
		forUpdate.setParam1("y");
		forUpdate.setIsDefault(CommonIsDefaultEnum.默认.getKey());

		forUpdate.setUpdateTime(DateUtil.date());
		forUpdate.setUpdateUserId(loginSysUser.getSysUserId());

		return invoiceBankInfoMapper.updateByPrimaryKeySelective(forUpdate);
	}

	@Override
	public InvoiceBankInfo getByDefault() {

		List<InvoiceBankInfo> result = invoiceBankInfoMapperEx.findAll(InvoiceBankInfoQueryCriteria
				.builder()
				.build()
		);

		List<Predicate<InvoiceBankInfo>> predicatesByFieldParam1Eqy = new ArrayList<>();
		predicatesByFieldParam1Eqy.add(r -> r.getParam1() != null && r.getParam1().equals("y") && r.getIsDefault().compareTo(CommonIsDefaultEnum.默认.getKey()) == 0);
		List<InvoiceBankInfo> predicatesByFieldParam1EqyFilter = AnLamdaUtils.filters(result, predicatesByFieldParam1Eqy);

		if (CollUtil.isNotEmpty(predicatesByFieldParam1EqyFilter)) {
			return predicatesByFieldParam1EqyFilter.get(0);
		} else if (CollUtil.isNotEmpty(result)) {
			return result.get(0);
		} else {
			// 初刀 吧
			return InvoiceBankInfo.builder()
					.id(-1L)
					.companyName("收款方信息异常")
					.taxpayersIDCode("信息异常")
					.bankAccount("信息异常")
					.bankName("信息异常")
					.supplyName("信息异常")
					.tel("信息异常")
					.address("信息异常")
					.param1("n")
					.param2("")
					.createTime(DateUtil.date())
					.createUserId(1L)
					.updateTime(DateUtil.date())
					.updateUserId(1L)
					.isDefault(CommonIsDefaultEnum.正常.getKey())
					.enabled(CommonEnabledEnum.禁用.getKey())
					.deleted(CommonSoftDeleteEnum.删除.getKey())
					.personNameInvoice("信息异常")
					.personNameReview("信息异常")
					.personNameCashier("信息异常")
					.sysUserIdInvoice(-1L)
					.sysUserIdReview(-1L)
					.sysUserIdCashier(-1L)
					.singleInvoiceMaxAmount1(BigDecimal.ONE)
					.singleInvoiceMaxAmount2(BigDecimal.ONE)
					.singleInvoiceMaxAmount3(BigDecimal.ONE)
					.singleInvoiceMaxAmount4(BigDecimal.ONE)
					.invoiceState(1)
					.invoiceType(1)
					.invoiceName("信息异常")
					.invoicePhone("信息异常")
					.invoiceProvice(-1)
					.invoiceCity(-1)
					.invoiceCounty(-1)
					.invoiceAddress("信息异常")
					.invoiceBank("信息异常")
					.invoiceAccount("信息异常")
					.invoiceBankAccountNumber("信息异常")
					.invoiceAddressPhone("信息异常")
					.serialNumber("信息异常")
					.build();
		}


	}


	public InvoiceBankInfo getInvoiceBankInfoById(Long invoiceBankInfoId) {
		InvoiceBankInfo entity = invoiceBankInfoMapper.selectByPrimaryKey(invoiceBankInfoId);
		return entity;
	}

	/**
	 * 此方法的目的为了啥子?
	 * TMD 有人把之前的收款方物理删除了,虽然后边做了逻辑删除,但老的对账单引用的收款方还是有可能会错的,老数据就不修了
	 * 哪为什么会设置为可以物理删除呢? 不要问我,我接手时就是这样了,后边改逻辑删除也是我发现的问题后修改的
	 * getByDefault 也是有可能为null,产品要求的,什么要求
	 * 设置默认逻辑是会将被设置的设为默认,同时清除别的默认,
	 * 但,已经是默认的能清除默认,此时,就没有默认了
	 *
	 * @param invoiceBankInfoId
	 * @return
	 */
	public InvoiceBankInfo getInvoiceBankInfoByIdOrNullByDefault(Long invoiceBankInfoId) {

		InvoiceBankInfo resultEntity = null;

		if (ObjectUtil.isNotNull(invoiceBankInfoId)) {
			resultEntity = getInvoiceBankInfoById(invoiceBankInfoId);
		}

		if (ObjectUtil.isNull(resultEntity)) {
			resultEntity = getByDefault();
		}

		return resultEntity;
	}

	public InvoiceBankInfoVo getInvoiceBankInfoByInvoiceApplyIdOrNullByDefault(Long invoiceApplyId) {

		InvoiceBankInfoVo invoiceBankInfoVo = null;

		List<Long> affectedAccountingOrderIds = invoiceApplyXGoodsService.getAffectedAccountingOrderIdsByInvoiceApplyId(invoiceApplyId);

		if (CollUtil.isEmpty(affectedAccountingOrderIds)) {
			return null;
		}


		/****************************************** 对账单VO start ******************************************/

		AccountingOrderScoreCustomerListItemVo accountingOrderScoreCustomerVo = accountingScoreCustomerService.getAccountingOrderScoreCustomerVoByAccountingOrderId(
				AccountingOrderScoreCustomerOpDetailQueryCriteria.builder().accountingOrderId(affectedAccountingOrderIds.get(0)).build(),
				LoginSysUser.builder().build()
		);

		/****************************************** 对账单VO   end ******************************************/


		if (StrUtil.isNotBlank(accountingOrderScoreCustomerVo.getInvoiceBankInfoSnapshot())) {
			invoiceBankInfoVo = AnJsonUtils.toObject(accountingOrderScoreCustomerVo.getInvoiceBankInfoSnapshot(), InvoiceBankInfoVo.class);
		} else {
			InvoiceBankInfo invoiceBankInfo = invoiceBankInfoService.getInvoiceBankInfoByIdOrNullByDefault(accountingOrderScoreCustomerVo.getBankInfoId());
			invoiceBankInfoVo = AnBeanUtils.copy(invoiceBankInfo, InvoiceBankInfoVo.class);
		}

		return invoiceBankInfoVo;
	}

	public R<List<InvoiceBankInfo>> pageQuery(Map<String, Object> conditions, int pageNun, int pageSize) {

		// 样例 保留
//		InvoiceBankInfo invoiceBankInfoConditions = BeanUtils.mapToBean(conditions,InvoiceBankInfo.class);

		InvoiceBankInfoExample          example  = new InvoiceBankInfoExample();
		InvoiceBankInfoExample.Criteria criteria = example.createCriteria();

		PageHelper.startPage(pageNun, pageSize);
		List<InvoiceBankInfo>     resultList = invoiceBankInfoMapper.selectByExample(example);
		PageInfo<InvoiceBankInfo> page       = new PageInfo<InvoiceBankInfo>(resultList);
		PageHelper.clearPage();

		return new R<List<InvoiceBankInfo>>(page.getPageNum(), page.getPageSize(), (int) page.getTotal(), resultList);

	}

	public R<List<InvoiceBankInfoParam>> pageQuery(InvoiceBankInfoQueryCriteria queryCriteria, LoginSysUser loginSysUser) {

		PageHelper.startPage(queryCriteria.getPageNumber(), queryCriteria.getPageSize());
		List<InvoiceBankInfo>     resultList = query(queryCriteria, loginSysUser);
		PageInfo<InvoiceBankInfo> page       = new PageInfo<InvoiceBankInfo>(resultList);
		PageHelper.clearPage();

		List<InvoiceBankInfoParam> resultListAdditionalInfo = additionalInfo(resultList);

		return new R<List<InvoiceBankInfoParam>>(page.getPageNum(), page.getPageSize(), (int) page.getTotal(), resultListAdditionalInfo);
	}

	// 附加信息 // TODO 待优化
	public List<InvoiceBankInfoParam> additionalInfo(List<InvoiceBankInfo> resultList) {

		if (CollUtil.isEmpty(resultList)) {
			return null;
		}

		List<InvoiceBankInfoParam> resultListAdditionalInfo = new ArrayList<>();

		List<Long> sysUserIds = new ArrayList<>();

		List<Long> createUserIds = resultList.stream().filter(o -> o.getCreateUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getCreateUserId())).map(o -> o.getCreateUserId()).collect(Collectors.toList());
		List<Long> updateUserIds = resultList.stream().filter(o -> o.getUpdateUserId() != null).filter(AnLamdaUtils.distinctByKey(o -> o.getUpdateUserId())).map(o -> o.getUpdateUserId()).collect(Collectors.toList());

		sysUserIds.addAll(createUserIds);
		sysUserIds.addAll(updateUserIds);

		sysUserIds = sysUserIds.stream().distinct().collect(Collectors.toList());

		log.info("\n{}", JSONUtil.toJsonStr(sysUserIds));

		Map<Long, SysUser> sysUserMap = sysUserService.convertSysUserIds2MapSysUserId2Entity(sysUserIds);

		for (InvoiceBankInfo entity : resultList) {

			InvoiceBankInfoParam vo = AnBeanUtils.copy(entity, InvoiceBankInfoParam.class);

			// 再补个
			if (sysUserMap.get(vo.getCreateUserId()) != null) {
				vo.setCreateUserName(sysUserMap.get(entity.getCreateUserId()).getFullname());
			} else if (entity.getCreateUserId().equals(1L)) {
				vo.setCreateUserName("系统");
			}

			if (sysUserMap.get(vo.getUpdateUserId()) != null) {
				vo.setUpdateUserName(sysUserMap.get(entity.getUpdateUserId()).getFullname());
			} else if (entity.getCreateUserId().equals(1L)) {
				vo.setUpdateUserName("系统");
			}

			resultListAdditionalInfo.add(vo);
		}

		return resultListAdditionalInfo;
	}

	@Override
	public List<InvoiceBankInfo> query(InvoiceBankInfoQueryCriteria queryCriteria, LoginSysUser loginSysUser) {

		List<InvoiceBankInfo> resultList = invoiceBankInfoMapperEx.findAll(queryCriteria);
		return resultList;
	}


	/****************************************** 工具方法 start ******************************************/

	public Map<String, InvoiceBankInfo> convertToMapStringEntity() {

		Map<String, InvoiceBankInfo> result = new HashMap<>();

		InvoiceBankInfoExample          example  = new InvoiceBankInfoExample();
		InvoiceBankInfoExample.Criteria criteria = example.createCriteria();

		List<InvoiceBankInfo> resultList = invoiceBankInfoMapper.selectByExample(example);

		if (CollUtil.isNotEmpty(resultList)) {
			result = resultList.stream().collect(Collectors.toMap(InvoiceBankInfo::getCompanyName, v -> v, (k, v) -> v));
		}

		return result;

	}

	/**
	 * InvoiceBankInfoCriteria conditions
	 *
	 * @return
	 */
	public Map<String, String> convertToMapStringString() {

		Map<String, String> result = new HashMap<>();

		Map<String, InvoiceBankInfo> tmp = convertToMapStringEntity();

		tmp.forEach((companyName, entity) -> {
			result.put(companyName, AnJsonUtils.toJson(entity));
//			result.put(URLUtil.encode((companyName)), JsonUtils.toJson(entity));
		});

		return result;

	}


	/****************************************** 工具方法   end ******************************************/

	/****************************************** 缓存 start ******************************************/
	public void cacheInit() {

//		InvoiceBankInfoCriteria conditions = new InvoiceBankInfoCriteria();

		Map<String, String> mapValue = convertToMapStringString();

		// 验证
		redisService.hashSave(mapValue, RedisKeyPrefix.关联性校验_前缀, RedisKeyPrefix.关联性校验_销方主体_发票抬头.getKey(), BaseRedisConf.REFRESH_TOKEN_EXPIRE_TIME);

		// 测试过 结果与上边一个样
//		mapValue.forEach((companyName, entityJsonString) -> {
//			cacheService.hashSet(RedisKeyPrefix.关联性校验_前缀.getKey() + ":" + RedisKeyPrefix.关联性校验_销方主体_发票抬头.getKey(), companyName, entityJsonString);
//		});
	}

	public void cacheRefresh() {

		redisService.deleteKey(RedisKeyPrefix.关联性校验_前缀, RedisKeyPrefix.关联性校验_销方主体_发票抬头.getKey());
		cacheInit();
	}

	public void cacheRemove() {

		redisService.deleteKey(RedisKeyPrefix.关联性校验_前缀, RedisKeyPrefix.关联性校验_销方主体_发票抬头.getKey());
	}

	public String cacheGet(String hashTable, String keyField) {
//		return (String) cacheService.hashGetByKey(hashTable, URLUtil.encode(keyField));

		log.info("hashTable@{}@field@{}@cacheService@{}", hashTable, keyField, redisService);

//		hashTable@relation:sys_enterprise_ext_invoice:company_name@field@中航物业管理有限公司成都分公司@cacheService@cn.superdesk.uniorder.common.cache.impl.RedisServiceImpl@4435b6b
//		hashTable@relation:sys_enterprise_ext_invoice:company_name@field@中航物业管理有限公司济南分公司@cacheService@cn.superdesk.uniorder.common.cache.impl.RedisServiceImpl@643f6179
		return (String) redisService.hashGetByKey(hashTable, keyField);
	}
	/****************************************** 缓存   end ******************************************/
}
