package com.friday.custody.service.basicService.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.friday.custody.dao.AccountInfoDao;
import com.friday.custody.entity.AccountInfoEntity;
import com.friday.custody.entity.FundInfoEntity;
import com.friday.custody.enums.RetCodeEnum;
import com.friday.custody.exception.RRException;
import com.friday.custody.req.AccountInfoReq;
import com.friday.custody.req.QueryDataReq;
import com.friday.custody.service.basicService.AccountInfoService;
import com.friday.custody.service.logicService.DataProcessService;
import com.friday.custody.utils.PageUtil;
import com.friday.custody.utils.PageUtils;
import com.friday.custody.utils.Query;
import com.friday.custody.utils.R;
import com.friday.custody.vo.AccountInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


@Service("accountInfoService")
@Slf4j
public class AccountInfoServiceImpl extends ServiceImpl<AccountInfoDao, AccountInfoEntity>
        implements AccountInfoService, DataProcessService<AccountInfoEntity> {

    @Autowired
    private AccountInfoDao accountInfoDao;
    @Autowired
    private FundInfoServiceImpl fundInfoService;


    public List<String> queryFundCodeByTrustNo(String trustNo, String tenantName) {
        Map<String, Object> map = new HashMap<>();
        map.put("trustNo", trustNo);
        map.put("admin", tenantName);
        return baseMapper.queryFundCodeByTrustNo(map);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R saveData(String type, List<AccountInfoEntity> datas) {
        for (AccountInfoEntity entity : datas) {
            //如果fundCode为null，fundName不为null，则通过fundName查询fundCode
            if (StringUtils.isBlank(entity.getFundCode()) && StringUtils.isNotBlank(entity.getFundName())) {
                String fundCode = fundInfoService.getFundCodeByFundName(entity.getFundName(), entity.getTrustNo(), entity.getAdmin());
                entity.setFundCode(fundCode);
            }
            //如果fundCode不为null，fundName为null，则通过fundCode查询fundName
            if (StringUtils.isNotBlank(entity.getFundCode()) && StringUtils.isBlank(entity.getFundName())) {
                String fundName = fundInfoService.getFundNameByFundCode(entity.getFundCode(), entity.getTrustNo(), entity.getAdmin());
                entity.setFundName(fundName);
            }
            //如果fundCode，fundName为null，innerFundCode不为null则通过innerFundCode查询fundName，fundCode
            if (StringUtils.isBlank(entity.getFundCode()) && StringUtils.isBlank(entity.getFundName()) && StringUtils.isNotBlank(entity.getInnerFundCode())) {
                FundInfoEntity fundInfoEntity = fundInfoService.queryByInnerFundCode(entity.getTrustNo(), entity.getAdmin(), entity.getInnerFundCode());
                if (fundInfoEntity != null) {
                    entity.setFundCode(fundInfoEntity.getFundCode());
                    entity.setFundName(fundInfoEntity.getFundName());
                }
            }
            if ("43".equals(entity.getTrustNo())) {
                entity.setUniqueKey(entity.getAdmin() + entity.getTrustNo() + entity.getFundCode() + entity.getAccoTypeCode());
            } else {
                entity.setUniqueKey(entity.getBankAcco() + entity.getTrustNo() + entity.getAdmin());
            }
            //todo 需要写一个记录失败的表
        }

        List<AccountInfoEntity> uniqueAccountInfoList = datas.stream().collect(Collectors.collectingAndThen
                (Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing
                        (AccountInfoEntity::getUniqueKey))), ArrayList::new));

        List<String> rawUniqueKeyList = uniqueAccountInfoList
                .stream()
                .map(AccountInfoEntity::getUniqueKey)
                .collect(Collectors.toList());

        String ukList = String.join("--", rawUniqueKeyList);

        if (CollectionUtils.isNotEmpty(rawUniqueKeyList)) {
            Set<String> uniqueKeySet = baseMapper.queryUniqueKeyList(rawUniqueKeyList);
            if (CollectionUtils.isNotEmpty(uniqueKeySet)) {
                baseMapper.deleteByUniqueKeys(uniqueKeySet);
            }
        }
        boolean saveStatus = this.saveBatch(uniqueAccountInfoList);
        if (!saveStatus) {
            log.error("save AccountInfo failed:{}", ukList);
        }else {
            log.info("save accountInfo counts:{}", uniqueAccountInfoList.size());
        }
        return R.ok();
    }

    @Override
    public R queryData(QueryDataReq vo) {
        try {
            log.info("开始查询资金账户基本信息表...,租户信息为:{}", JSON.toJSONString(vo));
            //1 封装查询参数
            AccountInfoReq req = JSON.parseObject(vo.getParams(), AccountInfoReq.class);
            //1.1 封装分页查询参数
            Map<String, Object> pageParams = PageUtil.getPageParams(req);
            //1.2 封装查询参数
            QueryWrapper<AccountInfoEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("admin", vo.getTenantName());
            if (StringUtils.isNotBlank(req.getFundCode())) {
                queryWrapper.eq("fund_code", req.getFundCode());
            }
            if (StringUtils.isNotBlank(req.getInnerFundCode())) {
                queryWrapper.eq("inner_fund_code", req.getInnerFundCode());
            }
            if (StringUtils.isNotBlank(req.getAccoTypeCode())) {
                queryWrapper.eq("acco_type_code", req.getAccoTypeCode());
            }
            if (StringUtils.isNotBlank(req.getBankAcco())) {
                queryWrapper.eq("bank_acco", req.getBankAcco());
            }
            if (StringUtils.isNotBlank(req.getFundName())) {
                queryWrapper.likeRight("fund_name", req.getFundName());
            }

            //（按银行账号bankAcco（若存在）、基金备案编码fundCode（若存在）、
            // 基金内部代码innerFundCode（若存在）、账户类型accoTypeCode（若存在）、托管人编码trustNo逆序排列）
            queryWrapper.orderBy(true, false, "bank_acco", "fund_code", "inner_fund_code", "acco_type_code", "trust_no");

            //2 执行检索
            IPage<AccountInfoEntity> page = this.page(
                    new Query<AccountInfoEntity>().getPage(pageParams),
                    queryWrapper
            );
            //封装数据
            PageUtils pageUtils = new PageUtils(page);
            List<AccountInfoEntity> entities = page.getRecords();
            //entities 转vo
            ArrayList<AccountInfoVo> vos = new ArrayList<>();
            for (AccountInfoEntity entity : entities) {
                vos.add(AccountInfoVo.builder()
                        .id(entity.getId())
                        .fundCode(Objects.isNull(entity.getFundCode()) ? "" : entity.getFundCode())
                        .innerFundCode(entity.getInnerFundCode())
                        .fundName(entity.getFundName())
                        .accoTypeCode(StringUtils.isBlank(entity.getAccoTypeCode()) ? "" : entity.getAccoTypeCode())
                        .acctStatus(entity.getAcctStatus())
                        .nameInBank(entity.getNameInBank())
                        .bankAcco(entity.getBankAcco())
                        .branchBankName(entity.getBranchBankName())
                        .bankCode(entity.getBankCode())
                        .largePayAcco(entity.getLargePayAcco())
                        .currency(StringUtils.isBlank(entity.getCurrency()) ? "" : entity.getCurrency())
                        .trustNo(entity.getTrustNo())
                        .build());
            }
            pageUtils.setList(vos);
            log.info("资金账户基本信息查询成功...");
            return R.ok("资金账户基本信息查询成功").put("data", pageUtils);
        } catch (RRException rrException) {
            log.error("the QueryDataVo is :" + JSON.toJSONString(vo) + ".the AccountInfoServiceImpl RRException is :", rrException);
            return R.error(RetCodeEnum.OPERATION_ERROR.getCode(), rrException.getMsg());
        } catch (Exception e) {
            log.error("the QueryDataVo is :" + JSON.toJSONString(vo) + ".the AccountInfoServiceImpl Exception is :", e);
            return R.error(RetCodeEnum.OPERATION_ERROR.getCode(), "查询数据失败!");
        }
    }

    public List<String> getFundCodeList(String trustNo, String admin) {
        List<String> fundCodeList = accountInfoDao.getFundCodeList(trustNo, admin);
        log.info("AccountInfoServiceImpl_fundCodeList入参trustNo={},admin={},出参={}", trustNo, admin, fundCodeList);
        return fundCodeList;
    }

    public String getDataByFundCode(String fundCode, String trustNo, String admin) {
        return accountInfoDao.getDataByFundCode(fundCode, trustNo, admin);
    }

    public void updateBankCodeAndCurrencyByBankAcco(String bankCode, String currency, String bankAcco, String trustno, String admin) {
        accountInfoDao.updateBankCodeAndCurrencyByBankAcco(bankCode, currency, bankAcco, trustno, admin);
    }

    public List<AccountInfoEntity> getDataList(String trustNo, String accoTypeCode, String admin) {
        return accountInfoDao.getDataList(trustNo, accoTypeCode, admin);
    }

    @Override
    public R updateData(String type, List<AccountInfoEntity> datas) {
        return null;
    }

    public AccountInfoEntity queryParam(String account, String trustNo) {
        return accountInfoDao.selectData(account, trustNo);
    }

    public List<AccountInfoEntity> getListByFundCode(String fundCode, String trustNo) {
        QueryWrapper<AccountInfoEntity> wrapper = new QueryWrapper<AccountInfoEntity>()
                .eq("fund_code", fundCode)
                .eq("trust_no", trustNo);
        List<AccountInfoEntity> accountInfoEntities = baseMapper.selectList(wrapper);
        log.info("getListByFundCode_fundCode={},trustNo={},result={}", fundCode, trustNo, JSON.toJSONString(accountInfoEntities));
        return accountInfoEntities;
    }

    public List<AccountInfoEntity> getListByAccTypeCode(String trustNo, String accountTypeCode) {
        QueryWrapper<AccountInfoEntity> queryWrapper = new QueryWrapper<AccountInfoEntity>();
        if (StringUtils.isNotBlank(trustNo)) {
            queryWrapper.eq("trust_no", trustNo);
        }
        if (StringUtils.isNotBlank(accountTypeCode)) {
            queryWrapper.eq("acco_type_code", accountTypeCode);
        }
        List<AccountInfoEntity> accountInfoEntities = baseMapper.selectList(queryWrapper);
        log.info("getListByAccTypeCode_accountTypeCode={},trustNo={},result={}", accountTypeCode, trustNo, JSON.toJSONString(accountInfoEntities));
        return accountInfoEntities;
    }

    public List<AccountInfoEntity> getListByAccTypeCodeAndAdmin(String trustNo, String accountTypeCode, String admin) {
        QueryWrapper<AccountInfoEntity> queryWrapper = new QueryWrapper<AccountInfoEntity>();
        if (StringUtils.isNotBlank(trustNo)) {
            queryWrapper.eq("trust_no", trustNo);
        }
        if (StringUtils.isNotBlank(accountTypeCode)) {
            queryWrapper.eq("acco_type_code", accountTypeCode);
        }
        if (StringUtils.isNotBlank(admin)) {
            queryWrapper.eq("admin", admin);
        }
        List<AccountInfoEntity> accountInfoEntities = baseMapper.selectList(queryWrapper);
        log.info("getListByAccTypeCode_accountTypeCode={},trustNo={},result={}", accountTypeCode, trustNo, JSON.toJSONString(accountInfoEntities));
        return accountInfoEntities;
    }

    public List<String> getBankAcco(String trustNo, String admin) {
        return accountInfoDao.getBankAcco(trustNo, admin);
    }

    public List<AccountInfoEntity> queryList(AccountInfoEntity accountInfoEntity) {
        QueryWrapper<AccountInfoEntity> queryWrapper = new QueryWrapper<AccountInfoEntity>();
        if (StringUtils.isNotBlank(accountInfoEntity.getTrustNo())) {
            queryWrapper.eq("trust_no", accountInfoEntity.getTrustNo());
        }
        if (StringUtils.isNotBlank(accountInfoEntity.getBankAcco())) {
            queryWrapper.eq("acco_type_code", accountInfoEntity.getAccoTypeCode());
        }
        if (StringUtils.isNotBlank(accountInfoEntity.getFundCode())) {
            queryWrapper.eq("fund_code", accountInfoEntity.getFundCode());
        }
        List<AccountInfoEntity> accountInfoEntities = baseMapper.selectList(queryWrapper);
        return accountInfoEntities;
    }
}