package com.crm.pay.service.impl;

import com.alibaba.fastjson.JSON;
import com.crm.pay.dao.mapper.SysRemittanceChannelMapper;
import com.crm.pay.dao.repository.SysRemittanceChannelRepository;
import com.crm.pay.entity.property.TelegraphicPayPropertyEntity;
import com.crm.pay.service.SysConfigService;
import com.crm.pay.service.SysRemittanceChannelService;
import com.crm.rely.backend.core.constant.Constants;
import com.crm.rely.backend.core.constant.ManagerConstant;
import com.crm.rely.backend.core.dto.base.BaseResultDto;
import com.crm.rely.backend.core.dto.base.PageDto;
import com.crm.rely.backend.core.dto.base.ResultWithPagerDto;
import com.crm.rely.backend.core.entity.base.SingleLongEntity;
import com.crm.rely.backend.core.exception.ServiceException;
import com.crm.rely.backend.core.pojo.table.SysConfigTable;
import com.crm.rely.backend.model.constant.ConfigConstants;
import com.crm.rely.backend.model.constant.PayConstants;
import com.crm.rely.backend.model.dto.sys.remittance.channel.SysRemittanceChannelDto;
import com.crm.rely.backend.model.dto.sys.remittance.channel.SysRemittanceChannelGetCodeDto;
import com.crm.rely.backend.model.entity.sys.config.SysConfigFinanceEntity;
import com.crm.rely.backend.model.entity.sys.remittance.channel.*;
import com.crm.rely.backend.model.pojo.table.SysRemittanceChannelTable;
import com.crm.rely.backend.model.pojo.view.SysRemittanceChannelView;
import com.crm.rely.backend.util.AESUtil;
import com.crm.rely.backend.util.FormatPage;
import com.crm.rely.backend.util.GetRandom;
import com.google.common.base.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.util.*;

@Service
public class SysRemittanceChannelServiceImpl implements SysRemittanceChannelService {

    @Autowired
    private SysRemittanceChannelRepository sysRemittanceChannelRepository;

    @Autowired
    private SysRemittanceChannelMapper sysRemittanceChannelMapper;

    @Autowired
    private SysConfigService sysConfigService;


    /**
     * 根据条件获取所有的通道
     *
     * @return
     * @throws Exception
     */
    @Override
    public BaseResultDto<List<SysRemittanceChannelDto>> getAllList(SysRemittanceChannelListEntity entity) throws Exception {
        List<SysRemittanceChannelView> sysRemittanceChannelViews =
                sysRemittanceChannelMapper.getAllByValidOrderBySubIndex(entity);

        if (sysRemittanceChannelViews == null || sysRemittanceChannelViews.size() <= 0) {
            return BaseResultDto.success();
        }
        List<SysRemittanceChannelDto> sysRemittanceChannelDtos = new ArrayList<>(sysRemittanceChannelViews.size());

        for (SysRemittanceChannelView sysRemittanceChannelView : sysRemittanceChannelViews) {
            SysRemittanceChannelDto sysRemittanceChannelDto = transform(sysRemittanceChannelView);

            //设置汇率
            BigDecimal rate = null;
            try {
                if (PayConstants.TELEGRAPHIC_PAY_TYPE_KEY.equals(sysRemittanceChannelView.getCode())
                        || PayConstants.UNION_PAY_TELEGRAPHIC_TWO.equals(sysRemittanceChannelView.getCode())
                        ||
                        (!Strings.isNullOrEmpty(sysRemittanceChannelView.getCode()) && sysRemittanceChannelView.getCode().startsWith(PayConstants.DIGITAL_PAY_TYPE_KEY))
                        || (sysRemittanceChannelView.getBankValid() != null
                        && !sysRemittanceChannelView.getBankValid().equals(1)
                        && !Strings.isNullOrEmpty(sysRemittanceChannelView.getCurrency())
                        && !Strings.isNullOrEmpty(sysRemittanceChannelView.getTransformCurrency()))) {
                    if (sysRemittanceChannelView.getRate() != null) {
                        rate = sysRemittanceChannelView.getRate();
                    } else {
                        rate = sysRemittanceChannelView.getFinanceRate();
                    }
                }
            } finally {
                sysRemittanceChannelDto.setRate(rate);
            }

            //设置是否要吧配置显示到前端 (电汇等通道需要显示到前端)
            if (!PayConstants.TELEGRAPHIC_PAY_TYPE_KEY.equals(sysRemittanceChannelDto.getCode())
                    && !PayConstants.UNION_PAY_TELEGRAPHIC_TWO.equals(sysRemittanceChannelDto.getCode())
                    && !PayConstants.UNION_PAY_TELEGRAPHIC_SPECIAL_TYPE_KEY.equals(sysRemittanceChannelDto.getCode())
                    &&
                    (Strings.isNullOrEmpty(sysRemittanceChannelView.getCode()) || !sysRemittanceChannelView.getCode().startsWith(PayConstants.DIGITAL_PAY_TYPE_KEY))
            ) {
                sysRemittanceChannelDto.setProperty(null);
            } else {
                String propertyString = null;
                if ((!Strings.isNullOrEmpty(sysRemittanceChannelView.getCode()) && sysRemittanceChannelView.getCode().startsWith(PayConstants.DIGITAL_PAY_TYPE_KEY))) {
                    propertyString = sysRemittanceChannelDto.getProperty();
                } else {
                    propertyString = getPropertyString(sysRemittanceChannelDto.getProperty());
                }

                sysRemittanceChannelDto.setProperty(propertyString);
            }
            sysRemittanceChannelDtos.add(sysRemittanceChannelDto);
        }
        return BaseResultDto.success(sysRemittanceChannelDtos);
    }

    /**
     * 根据实体查询通道 并返回值
     *
     * @param entity
     * @return
     * @throws Exception
     */
    @Override
    public BaseResultDto<SysRemittanceChannelDto> get(SysRemittanceChannelByCodeEntity entity) throws Exception {

        SysRemittanceChannelDto sysRemittanceChannelDto = getByCode(entity.getCode());
        if (sysRemittanceChannelDto == null) {
            return BaseResultDto.error();
        }

        return BaseResultDto.success(sysRemittanceChannelDto);
    }

    /**
     * 根据code获取通道返回数据
     *
     * @param code
     * @return
     * @throws Exception
     */
    @Override
    public SysRemittanceChannelDto getByCode(String code) throws Exception {
        SysRemittanceChannelTable sysRemittanceChancelTable = getSysRemittanceChannelByCode(code);
        if (sysRemittanceChancelTable == null) {
            return null;
        }
        SysConfigFinanceEntity sysConfigFinanceEntity = getFinanceConfigure();
        SysRemittanceChannelDto sysRemittanceChannelDto = transform(sysRemittanceChancelTable, sysConfigFinanceEntity);

        return sysRemittanceChannelDto;
    }

    @Override
    public SysRemittanceChannelTable getByCode(String code, boolean valid) throws Exception {
        SysRemittanceChannelTable sysRemittanceChancelTable;
        if (valid) {
            sysRemittanceChancelTable = sysRemittanceChannelRepository.getFirstByCodeAndValid(code, 1);
        } else {
            sysRemittanceChancelTable = sysRemittanceChannelRepository.getFirstByCode(code);
        }
        return sysRemittanceChancelTable;

    }

    /**
     * 获取通道配置实体
     *
     * @param code
     * @return
     * @throws Exception
     */
    @Override
    public SysRemittanceChannelTable getSysRemittanceChannelByCode(String code) throws ServiceException {
        return getSysRemittanceChannelByCode(code, true);
    }

    /**
     * 获取通道配置实体
     *
     * @param code  获取的是否是开启的通道
     * @param valid
     * @return
     * @throws ServiceException
     */
    @Override
    public SysRemittanceChannelTable getSysRemittanceChannelByCode(String code, boolean valid) throws ServiceException {
        SysRemittanceChannelTable sysRemittanceChancelTable;
        if (valid) {
            sysRemittanceChancelTable = sysRemittanceChannelRepository.getFirstByCodeAndValid(code, 1);
        } else {
            sysRemittanceChancelTable = sysRemittanceChannelRepository.getFirstByCode(code);
        }

        if (sysRemittanceChancelTable == null) {
            return null;
        }

        return sysRemittanceChancelTable;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void save(SysRemittanceChannelBatchUpdateEntity entity,
                     List<SysRemittanceChannelBasehUpdateEntity> entitys) throws ServiceException {

        List<SysRemittanceChannelTable> sysRemittanceChannelTables = sysRemittanceChannelRepository.findAll();

        if (entitys == null || entitys.size() <= 0) {
            sysRemittanceChannelRepository.delete(sysRemittanceChannelTables);
        }
        Map<String, String> mapCurrency = new HashMap<>(sysRemittanceChannelTables.size());
        Map<Long, SysRemittanceChannelTable> mapId = new HashMap<>(sysRemittanceChannelTables.size());
        for (SysRemittanceChannelTable sysRemittanceChannelTable : sysRemittanceChannelTables) {

            mapId.put(sysRemittanceChannelTable.getId(), sysRemittanceChannelTable);
        }

        List<SysRemittanceChannelTable> sysRemittanceChannelSaveTable = new ArrayList<>(entitys.size());
        int size = entitys.size();
        for (int i = 0; i < size; i++) {
            SysRemittanceChannelBasehUpdateEntity sysRemittanceChannelBasehUpdateEntity = entitys.get(i);

            String key = sysRemittanceChannelBasehUpdateEntity.getCode();
            if (mapCurrency.containsKey(key)) {
                throw ServiceException.exception(ManagerConstant.REMIT_CHANNEL_CODE_EXIST);
            } else {
                mapCurrency.put(key, key);
            }
            SysRemittanceChannelTable remittanceChannelTable;
            if (sysRemittanceChannelBasehUpdateEntity.getId() != null) {
                remittanceChannelTable = mapId.get(sysRemittanceChannelBasehUpdateEntity.getId());
                if (remittanceChannelTable == null) {
                    throw new ServiceException(Constants.INFO_NOT_FOUND);
                }
                if (!PayConstants.UNION_PAY_TELEGRAPHIC.equals(remittanceChannelTable.getCode()) && !PayConstants.DIGITAL_PAY_TYPE_KEY.equals(remittanceChannelTable.getCode())
                        && !PayConstants.QR_CODE_KEY.equals(remittanceChannelTable.getCode())
                ) {
                    sysRemittanceChannelBasehUpdateEntity.setProperty(remittanceChannelTable.getProperty());
                }
                BeanUtils.copyProperties(sysRemittanceChannelBasehUpdateEntity, remittanceChannelTable);

                mapId.remove(remittanceChannelTable.getId());
            } else {
                remittanceChannelTable = new SysRemittanceChannelTable();
                BeanUtils.copyProperties(sysRemittanceChannelBasehUpdateEntity, remittanceChannelTable);
                remittanceChannelTable.setAddIp(sysRemittanceChannelBasehUpdateEntity.getModifyIp());
                remittanceChannelTable.setAddUser(sysRemittanceChannelBasehUpdateEntity.getModifyUser());
                remittanceChannelTable.setAddTime(sysRemittanceChannelBasehUpdateEntity.getModifyTime());
                remittanceChannelTable.setModifyTime(null);
                remittanceChannelTable.setModifyIp(null);
                remittanceChannelTable.setModifyUser(null);
            }


            sysRemittanceChannelSaveTable.add(remittanceChannelTable);

        }

        if (sysRemittanceChannelSaveTable != null && !sysRemittanceChannelSaveTable.isEmpty()) {
            sysRemittanceChannelRepository.save(sysRemittanceChannelSaveTable);
        }


        if (!mapId.isEmpty()) {
            Collection<SysRemittanceChannelTable> channelTables = mapId.values();

            List<String> codes = new ArrayList<>(channelTables.size());
            for (SysRemittanceChannelTable sysRemittanceChannelTable :
                    channelTables) {
                codes.add(sysRemittanceChannelTable.getCode());
            }
            sysRemittanceChannelRepository.delete(channelTables);
        }

    }

    @Override
    public ResultWithPagerDto<SysRemittanceChannelDto> searchPageList(SysRemittanceChannelSearchEntity entity) throws ServiceException {
        //创建有序map map为排序字段
        Map<String, String> map = new LinkedHashMap<>(1);
        map.put("subIndex", "asc");
        map.put("addTime", "desc");
        Pageable pageable = FormatPage.formatPageable(entity.getPage(), map);

        Specification specification = getSpecification(entity);

        Page<SysRemittanceChannelTable> sysRemittanceChannelTables =
                sysRemittanceChannelRepository.findAll(specification, pageable);

        long count = sysRemittanceChannelTables.getTotalElements();
        PageDto pageDto = PageDto.format(entity.getPage(), count);

        if (count <= 0) {
            return ResultWithPagerDto.success(pageDto);
        }

        List<SysRemittanceChannelDto> sysRemittanceChannelSearchDtos =
                transform(sysRemittanceChannelTables.getContent());

        return ResultWithPagerDto.success(pageDto, sysRemittanceChannelSearchDtos);
    }

    @Override
    public List<SysRemittanceChannelDto> searchList() throws ServiceException {

        List<SysRemittanceChannelTable> sysRemittanceChannelTables = sysRemittanceChannelRepository.findAll();

        List<SysRemittanceChannelDto> transforms = transform(sysRemittanceChannelTables);
        if (transforms == null || transforms.size() <= 0) {
            return null;
        }

        return transforms;
    }

    @Override
    public List<SysRemittanceChannelGetCodeDto> getCodeList() throws ServiceException {

        List<SysRemittanceChannelTable> sysRemittanceChannelTables = sysRemittanceChannelRepository.findAll();

        List<SysRemittanceChannelGetCodeDto> transforms = transformGetCode(sysRemittanceChannelTables);
        if (transforms == null || transforms.size() <= 0) {
            return null;
        }
        return transforms;
    }

    @Override
    public SysRemittanceChannelDto searchSingle(SingleLongEntity entity) throws ServiceException {
        SysRemittanceChannelTable sysRemittanceChannelTable =
                sysRemittanceChannelRepository.getFirstById(entity.getId());
        if (sysRemittanceChannelTable == null) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }
        SysRemittanceChannelDto sysRemittanceChannelSearchDto = transform(sysRemittanceChannelTable);

        return sysRemittanceChannelSearchDto;
    }

    private Specification getSpecification(SysRemittanceChannelSearchEntity entity) {

        Specification<SysRemittanceChannelTable> specification = (root, query, cb) -> {

            List<Predicate> predicates = new ArrayList<>(5);
            if (!Strings.isNullOrEmpty(entity.getName())) {
                predicates.add(cb.equal(root.get("name").as(String.class), entity.getName()));
            }
            if (!Strings.isNullOrEmpty(entity.getCode())) {
                predicates.add(cb.equal(root.get("code").as(String.class), entity.getCode()));
            }
            if (entity.getValid() != null) {
                predicates.add(cb.equal(root.get("valid").as(String.class), entity.getValid()));
            }

            Predicate[] pre = new Predicate[predicates.size()];

            return query.where(predicates.toArray(pre)).getRestriction();
        };

        return specification;
    }

    private List<SysRemittanceChannelDto> transform(List<SysRemittanceChannelTable> sysRemittanceChannelTables) throws ServiceException {
        SysConfigFinanceEntity sysConfigFinanceEntity = getFinanceConfigure();
        return transform(sysRemittanceChannelTables, sysConfigFinanceEntity);
    }

    private List<SysRemittanceChannelDto> transform(List<SysRemittanceChannelTable> sysRemittanceChannelTables,
                                                    SysConfigFinanceEntity sysConfigFinanceEntity) {

        if (sysRemittanceChannelTables == null || sysRemittanceChannelTables.size() <= 0) {
            return null;
        }

        List<SysRemittanceChannelDto> sysRemittanceChannelSearchDtos =
                new ArrayList<>(sysRemittanceChannelTables.size());
        sysRemittanceChannelTables.forEach(value -> {
            try {
                sysRemittanceChannelSearchDtos.add(transform(value, sysConfigFinanceEntity));
            } catch (ServiceException e) {
                e.printStackTrace();
            }
        });

        return sysRemittanceChannelSearchDtos;
    }

    private SysRemittanceChannelDto transform(SysRemittanceChannelTable sysRemittanceChannelTable) throws ServiceException {
        SysRemittanceChannelDto sysRemittanceChannelDto = new SysRemittanceChannelDto();
        BeanUtils.copyProperties(sysRemittanceChannelTable, sysRemittanceChannelDto);
        return sysRemittanceChannelDto;
    }

    private SysRemittanceChannelDto transform(SysRemittanceChannelTable sysRemittanceChannelTable,
                                              SysConfigFinanceEntity sysConfigFinanceEntity) throws ServiceException {
        SysRemittanceChannelDto sysRemittanceChannelDto = new SysRemittanceChannelDto();
        BeanUtils.copyProperties(sysRemittanceChannelTable, sysRemittanceChannelDto);
        sysRemittanceChannelDto.setMaxAmount(sysConfigFinanceEntity.getMaxDeposit());
        sysRemittanceChannelDto.setMinAmount(sysConfigFinanceEntity.getMinDeposit());
        sysRemittanceChannelDto.setRate(sysConfigFinanceEntity.getDepositRate());
        if (!PayConstants.QR_CODE_KEY.equals(sysRemittanceChannelTable.getCode()) && !PayConstants.UNION_PAY_TELEGRAPHIC.equals(sysRemittanceChannelTable.getCode()) && !PayConstants.DIGITAL_PAY_TYPE_KEY.equals(sysRemittanceChannelTable.getCode())) {
            sysRemittanceChannelDto.setProperty(null);
        }
        return sysRemittanceChannelDto;
    }

    private List<SysRemittanceChannelGetCodeDto> transformGetCode(List<SysRemittanceChannelTable> sysRemittanceChannelTables) {

        if (sysRemittanceChannelTables == null || sysRemittanceChannelTables.size() <= 0) {
            return null;
        }

        List<SysRemittanceChannelGetCodeDto> sysRemittanceChannelGetCodeDtos =
                new ArrayList<>(sysRemittanceChannelTables.size());
        sysRemittanceChannelTables.forEach(value -> sysRemittanceChannelGetCodeDtos.add(transformGetCode(value)));

        return sysRemittanceChannelGetCodeDtos;
    }

    private SysRemittanceChannelGetCodeDto transformGetCode(SysRemittanceChannelTable sysRemittanceChannelTable) {
        SysRemittanceChannelGetCodeDto sysRemittanceChannelGetCodeDto = new SysRemittanceChannelGetCodeDto();
        BeanUtils.copyProperties(sysRemittanceChannelTable, sysRemittanceChannelGetCodeDto);
        return sysRemittanceChannelGetCodeDto;
    }

    private SysConfigFinanceEntity getFinanceConfigure() throws ServiceException {

        SysConfigTable sysConfigTable = sysConfigService.getByCode(ConfigConstants.FINANCE_CONFIGURE);
        SysConfigFinanceEntity financeEntity = JSON.parseObject(sysConfigTable.getValue(),
                SysConfigFinanceEntity.class);
        if (financeEntity == null) {
            throw ServiceException.exception(Constants.SYSTEM_ERROR);
        }
        return financeEntity;
    }

    /**
     * 设置通道配置 吧需要填写的银行信息的备注码在这里做随机出来
     *
     * @param propertyString
     * @return
     */
    private String getPropertyString(String propertyString) {
        try {
            List<TelegraphicPayPropertyEntity> propertys = JSON.parseArray(propertyString,
                    TelegraphicPayPropertyEntity.class);
            for (TelegraphicPayPropertyEntity property : propertys) {
                //随机6位数 返回到前端给客户填写
                String bankMsg = GetRandom.getRandom(6);
                property.setBankMsg(bankMsg);
            }
            propertyString = JSON.toJSONString(propertys);
        } catch (Exception e) {
            try {
                TelegraphicPayPropertyEntity property = JSON.parseObject(propertyString,
                        TelegraphicPayPropertyEntity.class);
                //随机6位数 返回到前端给客户填写
                String bankMsg = GetRandom.getRandom(6);
                property.setBankMsg(bankMsg);
                propertyString = JSON.toJSONString(property);
            } catch (Exception ee) {
                return null;
            }

        }
        return propertyString;
    }

    private String getPropertyKey() throws ServiceException {
        SysConfigTable table = sysConfigService.getByCode(ConfigConstants.FINANCE_PROPERTY_KEY);
        if (table == null) {
            throw ServiceException.exception(Constants.SYSTEM_ERROR);
        }
        return table.getValue();
    }

}
