package com.cool.store.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.cool.store.constants.RedisConstant;
import com.cool.store.context.CurrentUserHolder;
import com.cool.store.context.LoginUserInfo;
import com.cool.store.dao.EnterpriseUserDAO;
import com.cool.store.dao.WithdrawApplicationDAO;
import com.cool.store.dao.wallet.WalletTradeDAO;
import com.cool.store.dto.wallet.AccountWithdrawerDTO;
import com.cool.store.dto.wallet.TradeRecordDTO;
import com.cool.store.dto.wallet.WithdrawApplicationDTO;
import com.cool.store.entity.WithdrawApplicationDO;
import com.cool.store.entity.wallet.WalletTradeDO;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.enums.fees.AllocationPayStatusEnum;
import com.cool.store.enums.wallet.TradeTypeEnum;
import com.cool.store.enums.wechat.WalletTypeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.WithdrawApplicationPageRequest;
import com.cool.store.request.WithdrawApplicationRequest;
import com.cool.store.request.wallet.AccountWithdrawerRequest;
import com.cool.store.request.wallet.BillDetailRequest;
import com.cool.store.service.WithdrawApplicationService;
import com.cool.store.service.wallet.WalletApiService;
import com.cool.store.utils.GenerateNoUtil;
import com.cool.store.utils.RedisUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.cool.store.enums.wallet.WalletTradeModuleEnum.STANDARD_STORE;
import static com.cool.store.enums.wallet.WalletTradeModuleEnum.TRANSFER;

/**
 * 提现申请 Service 实现类
 */
@Service
@Slf4j
public class WithdrawApplicationServiceImpl implements WithdrawApplicationService {

    @Resource
    private WithdrawApplicationDAO withdrawApplicationDAO;

    @Resource
    RedisUtil redisUtil;

    @Resource
    WalletApiService walletApiService;

    @Resource
    WalletTradeDAO walletTradeDAO;

    @Resource
    EnterpriseUserDAO enterpriseUserDAO;

    private static final String WITHDRAW_ORDER_PREFIX = "TX";

    @Override
    public PageInfo<WithdrawApplicationDTO> page(WithdrawApplicationPageRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<WithdrawApplicationDTO> responses = withdrawApplicationDAO.pageQuery(request);
        Set<String> userIdList = responses.stream()
                .filter(x ->  StringUtils.isNotBlank(x.getCreateUserId()))
                .flatMap(x -> Stream.of( x.getCreateUserId()))
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());
        Map<String, String> userNameMap = enterpriseUserDAO.getUserNameMap(new ArrayList<>(userIdList));
        responses.stream().forEach(x->{
            x.setCreateUserName(userNameMap.get(x.getCreateUserId()));
        });
        return new PageInfo<>(responses);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(WithdrawApplicationRequest request) {
        String userId = CurrentUserHolder.getUserId();
        String withdrawNo = GenerateNoUtil.generateNo(WITHDRAW_ORDER_PREFIX);

        WithdrawApplicationDO withdrawApplication = WithdrawApplicationDO.builder()
                .withdrawNo(withdrawNo)
                .accountName(request.getAccountName())
                .accountNo(request.getAccountNo())
                .amount(request.getAmount())
                .bankCardNo(request.getBankCardNo())
                .bankName(request.getBankName())
                .status(AllocationPayStatusEnum.UNPAID.getStatus())
                .createUserId(userId)
                .createTime(new Date())
                .updateTime(new Date())
                .build();

        int result = withdrawApplicationDAO.insert(withdrawApplication);
        return result > 0;
    }

    @Override
    public Boolean confirmWithdraw(Long id) {
        LoginUserInfo user = CurrentUserHolder.getUser();
        String lockKey = MessageFormat.format(RedisConstant.WALLET_WITHDRAW_LOCK, id);
        boolean lock = redisUtil.tryLock(lockKey, id.toString(), 1, TimeUnit.SECONDS);
        if (!lock) {
            throw new ServiceException(ErrorCodeEnum.TRANSFER_ING);
        }
        WithdrawApplicationDO withdrawApplicationDO = withdrawApplicationDAO.getById(id);
        if (Objects.isNull(withdrawApplicationDO)){
            throw new ServiceException(ErrorCodeEnum.WITHDRAW_APPLY_NOT_EXIST);
        }
        if (!AllocationPayStatusEnum.UNPAID.getStatus().equals(withdrawApplicationDO.getStatus())){
            throw new ServiceException(ErrorCodeEnum.NOT_SUPPORT_OPERATION);
        }
        //开始提现
        AccountWithdrawerRequest request = new AccountWithdrawerRequest();
        request.setAccNo(withdrawApplicationDO.getAccountNo());
        request.setAmount(withdrawApplicationDO.getAmount().toPlainString());
        request.setReqNo(withdrawApplicationDO.getWithdrawNo());
        request.setWalletType(WalletTypeEnum.ONLINE_BANK.getType());
        AccountWithdrawerDTO accountWithdrawerDTO = walletApiService.accountWithdrawer(request);

        withdrawApplicationDO.setStatus(accountWithdrawerDTO.getTradeStatus());
        withdrawApplicationDAO.update(withdrawApplicationDO);
        //保存交易单
        WalletTradeDO walletTrade = new WalletTradeDO();
        //支付中 通过查询详情获取是否是否支付成功
        walletTrade.setPayStatus(AllocationPayStatusEnum.PAYING.getStatus());
        walletTrade.setModule(TRANSFER.getModule());
        walletTrade.setPayNo(withdrawApplicationDO.getWithdrawNo());
        walletTrade.setTradeId(String.valueOf(accountWithdrawerDTO.getTradeId()));
        walletTrade.setType(TradeTypeEnum.FEE_ADJUSTMENT_ORDER.getStatus());
        walletTrade.setPayUserName(user.getName());
        walletTrade.setPayAmount(new BigDecimal(accountWithdrawerDTO.getAmount()));
        walletTrade.setPayStatus(accountWithdrawerDTO.getTradeStatus());
        walletTrade.setPayTime(new Date());
        walletTrade.setCreateTime(new Date());
        walletTradeDAO.insertSelective(walletTrade);
        return Boolean.TRUE;
    }

    @Override
    @Transactional
    public Boolean updateTrade(WalletTradeDO walletTradeDO) {
        log.info("confirmWithdraw_updateTrade:{}", JSONObject.toJSONString(walletTradeDO));
        WithdrawApplicationDO withdraw = withdrawApplicationDAO.getByWithdrawNo(walletTradeDO.getPayNo());
        if (Objects.isNull(withdraw)){
            return Boolean.FALSE;
        }
        try {
            //查询详情
            BillDetailRequest billDetailRequest = new BillDetailRequest();
            billDetailRequest.setTradeId(Long.valueOf(walletTradeDO.getTradeId()));
            TradeRecordDTO billDetail = walletApiService.getBillDetail(billDetailRequest);
            withdraw.setFailReason(billDetail.getErrMsg());
            withdraw.setStatus(billDetail.getTradeStatus());
            withdrawApplicationDAO.update(withdraw);
            walletTradeDO.setPayStatus(billDetail.getTradeStatus());
            walletTradeDAO.updateByPrimaryKeySelective(walletTradeDO);
        }catch (Exception e){
            log.info("confirmWithdraw_error:{}",e.getMessage());
        }
        return Boolean.TRUE;
    }

}
