package com.crm.pay.service.impl;

import com.alibaba.fastjson.JSON;
import com.crm.pay.dao.mapper.FinanceDepositMapper;
import com.crm.pay.dao.repository.CustomInfoRepository;
import com.crm.pay.dao.repository.FinanceDepositRepository;
import com.crm.pay.entity.FinanceDepositCallbackUpdateEntity;
import com.crm.pay.service.CustomLoginService;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.SysConfigService;
import com.crm.pay.service.SysRemittanceChannelService;
import com.crm.rely.backend.configuration.LocaleMessage;
import com.crm.rely.backend.core.constant.Constants;
import com.crm.rely.backend.core.constant.EmailSendEnum;
import com.crm.rely.backend.core.constant.MapConstants;
import com.crm.rely.backend.core.constant.StatusConstants;
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.system.email.SysEmailSendEntity;
import com.crm.rely.backend.core.entity.web.notice.record.WebNoticeRecordAndEmailMqEntity;
import com.crm.rely.backend.core.exception.PayValidatedException;
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.EmailTemplateConstants;
import com.crm.rely.backend.model.constant.PayConstants;
import com.crm.rely.backend.model.dto.finance.deposit.FinanceDepositDto;
import com.crm.rely.backend.model.entity.finance.deposit.FinanceDepositAddEntity;
import com.crm.rely.backend.model.entity.finance.deposit.FinanceDepositApproveEntity;
import com.crm.rely.backend.model.entity.finance.deposit.FinanceDepositDeleteEntity;
import com.crm.rely.backend.model.entity.finance.deposit.FinanceDepositSearchListEntity;
import com.crm.rely.backend.model.entity.sys.config.SysConfigFinanceEntity;
import com.crm.rely.backend.model.pojo.table.CustomInfoTable;
import com.crm.rely.backend.model.pojo.table.CustomLoginTable;
import com.crm.rely.backend.model.pojo.table.FinanceDepositTable;
import com.crm.rely.backend.model.pojo.table.SysRemittanceChannelTable;
import com.crm.rely.backend.model.pojo.view.FinanceDepositView;
import com.crm.rely.backend.model.util.CustomInfoUtil;
import com.crm.rely.backend.service.EmailService;
import com.crm.rely.backend.service.MqSendService;
import com.crm.rely.backend.util.DateUtil;
import com.crm.rely.backend.util.GetRandom;
import com.google.common.base.Strings;
import lombok.extern.log4j.Log4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * @description:
 * @author: houn
 * @create: 2019-05-05 20:31
 */
@Log4j
@Service
public class FinanceDepositServiceImpl implements FinanceDepositService {

    @Autowired
    private LocaleMessage localeMessage;

    @Autowired
    private FinanceDepositRepository financeDepositRepository;

    @Autowired
    private FinanceDepositMapper financeDepositMapper;

    @Autowired
    private SysConfigService sysConfigService;

    @Autowired
    private CustomLoginService customLoginService;

    @Autowired
    private CustomInfoRepository customInfoRepository;
    @Autowired
    private SysRemittanceChannelService sysRemittanceChannelService;

    @Autowired
    private EmailService emailService;

    @Autowired
    private MqSendService mqSendService;

    /**
     * 保存入金信息
     *
     * @param balanceSaveEntity 入金实体
     * @return
     * @throws ServiceException
     * @throws PayValidatedException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public FinanceDepositTable save(FinanceDepositAddEntity balanceSaveEntity)
            throws ServiceException, PayValidatedException {
        //获取入金通道
        SysRemittanceChannelTable channel =
                sysRemittanceChannelService.getSysRemittanceChannelByCode(balanceSaveEntity.getPayType());

        if (channel == null) {
            throw new ServiceException(PayConstants.FINANCE_DEPOSIT_CHANNEL_NOT_EMPTY);
        }
        return save(balanceSaveEntity, channel);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public FinanceDepositTable save(FinanceDepositAddEntity balanceSaveEntity, SysRemittanceChannelTable channel)
            throws ServiceException, PayValidatedException {

        balanceSaveEntity.setCustomId(balanceSaveEntity.getAddUser());
        //验证通道
        if (channel == null) {
            throw new ServiceException(PayConstants.FINANCE_DEPOSIT_CHANNEL_NOT_EMPTY);
        }
        SysConfigFinanceEntity sysConfigFinanceEntity = getConfigFinance();
        if (balanceSaveEntity.getRate() == null) {
            balanceSaveEntity.setRate(sysConfigFinanceEntity.getDepositRate());
        }

        //验证订单金额是否在可入金额范围内
        validatedAmount(balanceSaveEntity, sysConfigFinanceEntity);

        //获取用户信息
        CustomInfoTable customInfoTable = getCustomInfo(balanceSaveEntity);

        //获取交易账号信息
        CustomLoginTable customLoginTable = getCustomLogin(balanceSaveEntity);

        Long cId = customLoginTable.getCId();


        //构建订单
        FinanceDepositTable financeDepositTable = new FinanceDepositTable();
        financeDepositTable.setCustomId(balanceSaveEntity.getCustomId());
        financeDepositTable.setCId(cId);
        financeDepositTable.setAmount(balanceSaveEntity.getAmount());
        financeDepositTable.setAgentId(customLoginTable.getAgentId());

        financeDepositTable.setStatus(StatusConstants.APPLY_STATUS);
        financeDepositTable.setDepositStatus(StatusConstants.MANAGER_PENDING_STATUS);
        financeDepositTable.setPayType(balanceSaveEntity.getPayType());
        financeDepositTable.setPayTypeName(channel.getName());
        financeDepositTable.setVoucherUrl(balanceSaveEntity.getVoucherUrl());

        //获取订单用户名称
        String name = CustomInfoUtil.getName(customInfoTable);
        String orderNo = getOrderNo();

        financeDepositTable.setRate(balanceSaveEntity.getRate());
        BigDecimal cnyAmount = financeDepositTable.getAmount().multiply(financeDepositTable.getRate());
        financeDepositTable.setCny(cnyAmount);
        financeDepositTable.setSerial(orderNo);
        financeDepositTable.setLogin(balanceSaveEntity.getLogin());
        financeDepositTable.setName(name);


        financeDepositTable.setAddIp(balanceSaveEntity.getAddIp());
        financeDepositTable.setAddTime(balanceSaveEntity.getAddTime());
        financeDepositTable.setAddUser(balanceSaveEntity.getAddUser());

        if (PayConstants.QR_CODE_KEY.equals(financeDepositTable.getPayType()) || PayConstants.DIGITAL_PAY_TYPE_KEY.equals(financeDepositTable.getPayType()) || PayConstants.UNION_PAY_TELEGRAPHIC.equals(financeDepositTable.getPayType())) {
            financeDepositTable.setCallbackStatus(StatusConstants.PAY_CALLBACK_COMPLETED_STATUS);
        } else {
            financeDepositTable.setCallbackStatus(StatusConstants.PAY_CALLBACK_PENDING_STATUS);
        }

        //保存订单信息
        financeDepositRepository.save(financeDepositTable);
        if (StatusConstants.PAY_CALLBACK_COMPLETED_STATUS.equals(financeDepositTable.getCallbackStatus())) {
            sendDepositEmail(financeDepositTable);
        }

        return financeDepositTable;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FinanceDepositTable approve(FinanceDepositApproveEntity entity) throws ServiceException {
        FinanceDepositTable financeDepositTable = financeDepositRepository.findFirstById(entity.getId());
        if (financeDepositTable == null) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }
        if (!StatusConstants.MANAGER_PENDING_STATUS.equals(financeDepositTable.getDepositStatus())
                || !StatusConstants.APPLY_STATUS.equals(financeDepositTable.getStatus())) {
            throw ServiceException.exception(Constants.CANNOT_APPROVE);
        }

        if (entity.getAmount() == null && entity.getCny() == null) {
            entity.setCny(financeDepositTable.getCny());
            entity.setAmount(financeDepositTable.getAmount());
        } else if (entity.getAmount() != null) {
            entity.setCny(entity.getAmount().multiply(financeDepositTable.getRate()));
        } else if (entity.getCny() != null) {

            BigDecimal amount = entity.getCny().divide(financeDepositTable.getRate(), 10, BigDecimal.ROUND_HALF_UP);
            entity.setAmount(amount);
        }

        BeanUtils.copyProperties(entity, financeDepositTable);

        financeDepositRepository.save(financeDepositTable);

//        if (StatusConstants.PASSED_STATUS.equals(financeDepositTable.getStatus())
//                && StatusConstants.MANAGER_COMPLETED_STATUS.equals(financeDepositTable.getDepositStatus())) {
//
//        }


        CustomInfoTable customInfoTable = customInfoRepository.findFirstById(financeDepositTable.getCustomId());
        if (customInfoTable == null) {
            throw new ServiceException(Constants.USER_NOT_EXIST_ERROR);
        }

        //调整客户是否有入金成功
        if (StatusConstants.PASSED_STATUS.equals(entity.getStatus())) {
            if (customInfoTable.getPayStatus() == null || !customInfoTable.getPayStatus().equals(1)) {
                customInfoTable.setPayStatus(1);
                customInfoRepository.save(customInfoTable);
            }
        }
        sendCustomDepositEmail(financeDepositTable, customInfoTable);
        return financeDepositTable;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(FinanceDepositDeleteEntity entity) throws ServiceException {
        List<FinanceDepositTable> allByIdIn = financeDepositRepository.findAllByIdIn(entity.getIds());
        if (allByIdIn == null || allByIdIn.size() <= 0) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }

        financeDepositRepository.delete(allByIdIn);
    }

    @Override
    public ResultWithPagerDto<FinanceDepositDto> searchPageList(FinanceDepositSearchListEntity entity) throws ServiceException {
        Integer count = financeDepositMapper.countList(entity);
        PageDto pageDto = PageDto.format(entity, count);
        if (count == null || count <= 0) {
            return ResultWithPagerDto.success(pageDto);
        }

        BaseResultDto<List<FinanceDepositDto>> listBaseResultDto = searchList(entity);

        return ResultWithPagerDto.success(pageDto, listBaseResultDto.getData());
    }

    @Override
    public BaseResultDto<List<FinanceDepositDto>> searchList(FinanceDepositSearchListEntity entity) throws ServiceException {

        List<FinanceDepositView> financeDepositViews = financeDepositMapper.searchList(entity);

        if (financeDepositViews == null || financeDepositViews.size() <= 0) {

            throw new ServiceException(Constants.SYSTEM_ERROR);
        }
        List<FinanceDepositDto> financeDepositDtos = new ArrayList<>(financeDepositViews.size());

        for (FinanceDepositView financeDepositView : financeDepositViews) {
            FinanceDepositDto transform = transform(financeDepositView);
            financeDepositDtos.add(transform);
        }

        return BaseResultDto.success(financeDepositDtos);
    }

    @Override
    public FinanceDepositDto searchSingle(Long id) throws ServiceException {
        FinanceDepositView financeDepositMapperSingle = financeDepositMapper.getOne(id);
        if (financeDepositMapperSingle == null) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }
        return transform(financeDepositMapperSingle);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCallback(FinanceDepositCallbackUpdateEntity financeDepositCallbackUpdateEntity) throws ServiceException {

        //获取订单
        FinanceDepositTable financeDepositTable =
                financeDepositRepository.findFirstBySerial(financeDepositCallbackUpdateEntity.getSerial());
        if (financeDepositTable == null) {
            throw new ServiceException(Constants.SYSTEM_ERROR);
        }
        if (StatusConstants.PAY_CALLBACK_COMPLETED_STATUS.equals(financeDepositTable.getCallbackStatus())) {
            return;
        }
        //填充订单数据
        if (!Strings.isNullOrEmpty(financeDepositCallbackUpdateEntity.getChannelSerial())) {
            financeDepositTable.setChannelSerial(financeDepositCallbackUpdateEntity.getChannelSerial());
        }
        financeDepositTable.setCallbackStatus(financeDepositCallbackUpdateEntity.getCallbackStatus());
        financeDepositTable.setModifyTime(new Date());

        financeDepositTable.setNote(financeDepositCallbackUpdateEntity.getNote());
        //根据回调实体中是否有金额判断回调订单金额可能存在变动 并再次进行计算填充
        if (financeDepositCallbackUpdateEntity.getAmount() != null) {
            financeDepositTable.setAmount(financeDepositCallbackUpdateEntity.getAmount());
            if (financeDepositCallbackUpdateEntity.getTransformAmount() != null) {
                financeDepositTable.setCny(financeDepositCallbackUpdateEntity.getTransformAmount());
            } else {
                BigDecimal rate = financeDepositTable.getRate();
                BigDecimal transformAmount = financeDepositCallbackUpdateEntity.getAmount().multiply(rate);
                financeDepositTable.setCny(transformAmount);
            }
        } else if (financeDepositCallbackUpdateEntity.getTransformAmount() != null) {
            financeDepositTable.setCny(financeDepositCallbackUpdateEntity.getTransformAmount());
            BigDecimal rate = financeDepositTable.getRate();
            BigDecimal amount = financeDepositTable.getCny().divide(rate, 10, BigDecimal.ROUND_HALF_UP);
            financeDepositTable.setAmount(amount);
        }
        if (StatusConstants.PAY_CALLBACK_COMPLETED_STATUS.equals(financeDepositTable.getCallbackStatus())) {
            financeDepositTable.setStatus(StatusConstants.PASSED_STATUS);
        }
        //更新订单
        financeDepositRepository.save(financeDepositTable);

        //发送成功处理
        if (StatusConstants.PAY_CALLBACK_COMPLETED_STATUS.equals(financeDepositTable.getCallbackStatus())) {
            //发送入金成功邮件
            sendDepositEmail(financeDepositTable);
        }
    }

    private FinanceDepositDto transform(FinanceDepositView financeDepositView) {
        FinanceDepositDto financeDepositDto = new FinanceDepositDto();
        BeanUtils.copyProperties(financeDepositView, financeDepositDto);
        return financeDepositDto;
    }

    private void sendDepositEmail(FinanceDepositTable table) throws ServiceException {

        SysConfigTable sysConfigTable = sysConfigService.getByCode(ConfigConstants.FINANCE_DEPOSIT_MANAGER_EMAIL);
        if (sysConfigTable == null) {
            throw new ServiceException(Constants.SYSTEM_ERROR);
        }
        String users = sysConfigTable.getValue();

        if (users == null) {
            throw new ServiceException(Constants.SYSTEM_ERROR);
        }
        //构建map 用于后面邮件模版替换
        Map<String, String> map = new HashMap<>(10);

        map.put(MapConstants.LOGIN, table.getLogin() + "");

        map.put(MapConstants.NAME, table.getName());

        map.put(MapConstants.DEPOSIT_AMOUNT, table.getAmount() == null ? "" : String.format("%.2f",
                table.getAmount().doubleValue()));
        map.put(MapConstants.APPLY_TIME, DateUtil.formatTime(table.getAddTime()));
        map.put(MapConstants.SERIAL, table.getSerial());
        map.put(MapConstants.DATE_TIME, DateUtil.formatTime(new Date()));

        SysEmailSendEntity sysEmailSendEntity = new SysEmailSendEntity();
        sysEmailSendEntity.setSubject("CWG DEPOSIT");
        sysEmailSendEntity.setEmailSendEnum(EmailSendEnum.FINANCE_DEPOSIT_NOTICE);
        sysEmailSendEntity.setMap(map);
        sysEmailSendEntity.setTemplateName(EmailTemplateConstants.FINANCE_DEPOSIT_NOTICE_NAME);
        sysEmailSendEntity.setUsers(users);
        try {
            emailService.sendEmail(sysEmailSendEntity);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void sendCustomDepositEmail(FinanceDepositTable table, CustomInfoTable customInfoTable) throws ServiceException {


        //构建map 用于后面邮件模版替换
        Map<String, String> map = new HashMap<>(10);
        String name = CustomInfoUtil.getName(customInfoTable);

        map.put(MapConstants.NAME, name);
        map.put(MapConstants.LOGIN, String.valueOf(table.getLogin()));

        map.put(MapConstants.DEPOSIT_AMOUNT, table.getAmount() == null ? "" : String.format("%.2f",
                table.getAmount().doubleValue()));
        map.put(MapConstants.DATE_TIME, DateUtil.formatTime(new Date()));
        map.put(MapConstants.APPROVE_DESC, table.getApproveDesc());
        map.put(MapConstants.APPROVE_STATUS, table.getStatus().equals(2) ? "通过" : "拒绝");

        SysEmailSendEntity sysEmailSendEntity = new SysEmailSendEntity();
        sysEmailSendEntity.setSubject("CWG DEPOSIT");
        sysEmailSendEntity.setEmailSendEnum(EmailSendEnum.CUSTOM_FINANCE_DEPOSIT_NOTICE);
        sysEmailSendEntity.setMap(map);

        sysEmailSendEntity.setTemplateName(EmailTemplateConstants.FINANCE_DEPOSIT_APPROVE_NOTICE_RESULT);

        sysEmailSendEntity.setUsers(customInfoTable.getEmail());
        try {
            emailService.sendEmail(sysEmailSendEntity);
            WebNoticeRecordAndEmailMqEntity mqEntity = new WebNoticeRecordAndEmailMqEntity(sysEmailSendEntity,
                    table.getCId(), table.getCustomId());
            mqSendService.send(Constants.WEB_NOTICE_PUT_RECORD, mqEntity);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private SysConfigFinanceEntity getConfigFinance() 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;
    }

    private void validatedAmount(FinanceDepositAddEntity balanceSaveEntity, SysConfigFinanceEntity financeEntity) throws ServiceException, PayValidatedException {
        if (balanceSaveEntity.getAmount().intValue() < financeEntity.getMinDeposit().intValue()) {
            throw new PayValidatedException(localeMessage.getMessage(PayConstants.FINANCE_DEPOSIT_AMOUNT_LESS_THAN,
                    PayConstants.FINANCE_DEPOSIT_AMOUNT_LESS_THAN) + financeEntity.getMinDeposit().intValue());
        }
        if (balanceSaveEntity.getAmount().intValue() > financeEntity.getMaxDeposit().intValue()) {
            throw new PayValidatedException(localeMessage.getMessage(PayConstants.FINANCE_DEPOSIT_AMOUNT_GREATER_THAN
                    , PayConstants.FINANCE_DEPOSIT_AMOUNT_GREATER_THAN) + financeEntity.getMaxDeposit().intValue());
        }
    }

    /**
     * 获取交易账户
     *
     * @param balanceSaveEntity
     * @return
     * @throws ServiceException
     */
    private CustomLoginTable getCustomLogin(FinanceDepositAddEntity balanceSaveEntity) throws ServiceException {
        CustomLoginTable customLoginTable = customLoginService.getByCustomIdAndLogin(balanceSaveEntity.getCustomId(),
                balanceSaveEntity.getLogin());
        if (customLoginTable == null) {
            throw ServiceException.exception(Constants.NOT_PERMIT);
        }
        return customLoginTable;
    }

    /**
     * 获取客户信息
     *
     * @param balanceSaveEntity
     * @return
     * @throws ServiceException
     */
    private CustomInfoTable getCustomInfo(FinanceDepositAddEntity balanceSaveEntity) throws ServiceException {
        CustomInfoTable customInfoTable = customInfoRepository.getFirstById(balanceSaveEntity.getCustomId());
        if (customInfoTable == null) {
            throw new ServiceException(Constants.USER_NOT_EXIST_ERROR);
        }

        return customInfoTable;
    }

    /**
     * 生成订单号
     *
     * @return 订单号
     */
    private String getOrderNo() {
        /**
         * 生成订单号
         */
        String orderNo = GetRandom.getOrderNo(PayConstants.DEPOSIT_HEAD);
        return orderNo;
    }

}
