package com.crm.pay.service.impl;

import com.alibaba.fastjson.JSON;
import com.crm.pay.dao.mapper.FinanceWithdrawMapper;
import com.crm.pay.dao.repository.FinanceWithdrawRepository;
import com.crm.pay.service.CustomInfoService;
import com.crm.pay.service.CustomLoginService;
import com.crm.pay.service.FinanceWithdrawService;
import com.crm.pay.service.SysConfigService;
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.pojo.table.SysConfigTable;
import com.crm.rely.backend.core.exception.ServiceException;
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.withdraw.FinanceWithdrawDto;
import com.crm.rely.backend.model.entity.finance.withdraw.FinanceWithdrawApproveEntity;
import com.crm.rely.backend.model.entity.finance.withdraw.FinanceWithdrawBaseAddEntity;
import com.crm.rely.backend.model.entity.finance.withdraw.FinanceWithdrawDeleteEntity;
import com.crm.rely.backend.model.entity.finance.withdraw.FinanceWithdrawSearchListEntity;
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.FinanceWithdrawTable;
import com.crm.rely.backend.model.pojo.view.FinanceWithdrawView;
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.service.RedisService;
import com.crm.rely.backend.util.DateUtil;
import com.crm.rely.backend.util.GetRandom;
import com.crm.rely.backend.util.UUIDUtil;
import lombok.extern.slf4j.Slf4j;
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.*;

/**
 * @author houn
 */
@Slf4j
@Service
public class FinanceWithdrawServiceImpl implements FinanceWithdrawService {
    @Autowired
    private LocaleMessage localeMessage;

    @Autowired
    private FinanceWithdrawRepository financeWithdrawRepository;

    @Autowired
    private FinanceWithdrawMapper financeWithdrawMapper;

    @Autowired
    private CustomInfoService customInfoService;

    @Autowired
    private CustomLoginService customLoginService;

    @Autowired
    private SysConfigService sysConfigService;

    @Autowired
    private EmailService emailService;

    @Autowired
    private MqSendService mqSendService;

    @Autowired
    private RedisService redisService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResultDto save(FinanceWithdrawBaseAddEntity entity) throws ServiceException {
        String uuid = UUIDUtil.getUUID();
        String key = this.getClass().toString() + "save" + entity.getCustomId();

        if (!redisService.tryLock(key, uuid
                , 5 * 60 * 1000)) {
            throw ServiceException.exception("no_repeat_submit_error");
        }
        CustomInfoTable customInfoTable = customInfoService.findFirstById(entity.getCustomId());
        if (customInfoTable == null) {
            throw new ServiceException(Constants.USER_NOT_EXIST_ERROR);
        }
        SysConfigFinanceEntity financeEntity = getConfigFinance();
        //验证最大最小入金
        validated(entity, financeEntity);

        BigDecimal cnyAmount = entity.getAmount().multiply(financeEntity.getWithdrawRate());
        entity.setCny(cnyAmount);
        entity.setRate(financeEntity.getWithdrawRate());
        if (entity.getSourceType().equals(2)) {
            customInfoService.updateUsdAmountById(entity.getCustomId(), entity.getAmount().negate(), "出金");
        }
        if (entity.getSourceType().equals(3)) {
            customInfoService.updateCnyAmountById(entity.getCustomId(), entity.getCny().negate(), "出金");
        }
        String name = CustomInfoUtil.getName(customInfoTable);

        CustomLoginTable customLoginTable = null;
        if (entity.getLogin() != null) {
            customLoginTable = customLoginService.getByCustomIdAndLogin(entity.getCustomId(), entity.getLogin());
            if (customLoginTable == null) {
                throw ServiceException.exception(Constants.LOGIN_NOT_NULL_ERROR);
            }
        }

        //构建实体
        FinanceWithdrawTable financeWithdrawTable = new FinanceWithdrawTable();
        BeanUtils.copyProperties(entity, financeWithdrawTable);

        financeWithdrawTable.setStatus(StatusConstants.APPLY_STATUS);
        financeWithdrawTable.setSerial(getOrderNo());
        financeWithdrawTable.setName(name);
        if (customLoginTable != null) {
            financeWithdrawTable.setLogin(customLoginTable.getLogin());
            financeWithdrawTable.setAgentId(customLoginTable.getAgentId());
        } else {
            financeWithdrawTable.setAgentId(customInfoTable.getAgentId());
        }
        financeWithdrawRepository.save(financeWithdrawTable);

        sendWithdrawEmail(financeWithdrawTable);

        return BaseResultDto.success();

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approve(FinanceWithdrawApproveEntity entity) throws ServiceException {
        FinanceWithdrawTable financeWithdrawTable = financeWithdrawRepository.findFirstById(entity.getId());
        if (financeWithdrawTable == null) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }
        if (!StatusConstants.APPLY_STATUS.equals(financeWithdrawTable.getStatus())) {
            throw ServiceException.exception(Constants.CANNOT_APPROVE);
        }

        BeanUtils.copyProperties(entity, financeWithdrawTable);

        financeWithdrawRepository.save(financeWithdrawTable);
        if (StatusConstants.REJECTED_STATUS.equals(financeWithdrawTable.getStatus())) {
            if (financeWithdrawTable.getSourceType().equals(2)) {
                customInfoService.updateUsdAmountById(financeWithdrawTable.getCustomId(),
                        financeWithdrawTable.getAmount(), "出金失败退款");
            }
            if (financeWithdrawTable.getSourceType().equals(3)) {
                customInfoService.updateCnyAmountById(financeWithdrawTable.getCustomId(),
                        financeWithdrawTable.getCny(), "出金失败退款");
            }
        }
        sendCustomEmail(financeWithdrawTable);
    }

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

        financeWithdrawRepository.delete(allByIdIn);
    }

    @Override
    public ResultWithPagerDto<FinanceWithdrawDto> searchList(FinanceWithdrawSearchListEntity entity) throws ServiceException {
        Integer count = financeWithdrawMapper.countList(entity);
        PageDto pageDto = PageDto.format(entity, count);
        if (count == null || count <= 0) {
            return ResultWithPagerDto.success(pageDto);
        }
        List<FinanceWithdrawView> financeWithdrawViews = financeWithdrawMapper.pageList(entity);

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

            throw new ServiceException(Constants.SYSTEM_ERROR);
        }
        List<FinanceWithdrawDto> financeWithdrawDtos = transform(financeWithdrawViews, true);

        return ResultWithPagerDto.success(pageDto, financeWithdrawDtos);
    }

    @Override
    public FinanceWithdrawDto searchSingle(Long id) throws ServiceException {
        FinanceWithdrawView view = financeWithdrawMapper.getOne(id);
        if (view == null) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }
        return transform(view);
    }

    private void sendWithdrawEmail(FinanceWithdrawTable table) throws ServiceException {

        SysConfigTable sysConfigTable = sysConfigService.getByCode(ConfigConstants.FINANCE_WITHDRAW_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.WITHDRAW_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_WITHDRAW_NOTICE);
        sysEmailSendEntity.setMap(map);
        sysEmailSendEntity.setTemplateName(EmailTemplateConstants.FINANCE_WITHDRAW_NOTICE_NAME);
        sysEmailSendEntity.setUsers(users);
        try {
            emailService.sendEmail(sysEmailSendEntity);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void sendCustomEmail(FinanceWithdrawTable table) throws ServiceException {

        CustomInfoTable customInfoTable = customInfoService.getById(table.getCustomId());
        if (customInfoTable == null) {
            throw new ServiceException(Constants.USER_NOT_EXIST_ERROR);
        }
        //构建map 用于后面邮件模版替换
        Map<String, String> map = new HashMap<>(10);

        map.put(MapConstants.NAME, table.getName());
        map.put(MapConstants.LOGIN, String.valueOf(table.getLogin()));
        map.put(MapConstants.WITHDRAW_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.setMap(map);

        sysEmailSendEntity.setTemplateName(EmailTemplateConstants.FINANCE_WITHDRAW_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 List<FinanceWithdrawDto> transform(List<FinanceWithdrawView> financeWithdrawViews, boolean isBalance) {
        List<FinanceWithdrawDto> financeWithdrawDtos = new ArrayList<>(financeWithdrawViews.size());

        for (FinanceWithdrawView view : financeWithdrawViews) {

            FinanceWithdrawDto transform = transform(view);
            financeWithdrawDtos.add(transform);
        }
        return financeWithdrawDtos;
    }

    private FinanceWithdrawDto transform(FinanceWithdrawView financeWithdrawView) {
        FinanceWithdrawDto dto = new FinanceWithdrawDto();
        BeanUtils.copyProperties(financeWithdrawView, dto);

        return dto;
    }

    /**
     * 验证数据
     *
     * @param entity
     * @throws ServiceException
     */
    public void validated(FinanceWithdrawBaseAddEntity entity, SysConfigFinanceEntity financeEntity) throws ServiceException {

        if (entity.getAmount().intValue() < financeEntity.getMinWithdraw().intValue()) {
            throw new ServiceException(localeMessage.getMessage(PayConstants.FINANCE_WITHDRAW_AMOUNT_LESS_THAN,
                    PayConstants.FINANCE_WITHDRAW_AMOUNT_LESS_THAN) + financeEntity.getMinWithdraw().intValue());
        }
    }

    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 String getOrderNo() {
        /**
         * 生成订单号
         */
        String orderNo = GetRandom.getOrderNo(PayConstants.WITHDRAW_HEAD);
        return orderNo;
    }
}
