package com.slodon.b2b2c.controller.seller.seller;

import com.alibaba.fastjson.JSON;
import com.slodon.b2b2c.core.constant.StoreOpenAccountConst;
import com.slodon.b2b2c.core.controller.BaseController;
import com.slodon.b2b2c.core.exception.MallException;
import com.slodon.b2b2c.core.response.JsonResult;
import com.slodon.b2b2c.core.response.PageVO;
import com.slodon.b2b2c.core.response.PagerInfo;
import com.slodon.b2b2c.core.response.SldResponse;
import com.slodon.b2b2c.core.util.AssertUtil;
import com.slodon.b2b2c.core.util.UserUtil;
import com.slodon.b2b2c.core.util.WebUtil;
import com.slodon.b2b2c.model.seller.StoreOpenAccountModel;
import com.slodon.b2b2c.model.seller.StoreWithdrawalModel;
import com.slodon.b2b2c.seller.example.StoreWithdrawalExample;
import com.slodon.b2b2c.seller.pojo.StoreOpenAccount;
import com.slodon.b2b2c.seller.pojo.StoreWithdrawal;
import com.slodon.b2b2c.seller.pojo.Vendor;
import com.slodon.b2b2c.starter.util.ZjPayUtil;
import com.slodon.b2b2c.vo.seller.StoreWithdrawalListVO;
import com.slodon.b2b2c.vo.seller.StoreZjAccountInfoVO;
import cpcn.institution.tools.util.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import payment.api.notice.Notice4658Request;
import payment.api.notice.NoticeRequest;
import payment.api.notice.NoticeResponse;
import payment.api.tx.foundationaccount.Tx4643Response;
import payment.api.tx.foundationaccount.Tx4691Response;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Api(tags = "seller-商户提现接口")
@Slf4j
@RestController
@RequestMapping("/v3/seller/seller/withdrawal")
public class SellerWithdrawalController extends BaseController {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private StoreOpenAccountModel storeOpenAccountModel;
    @Resource
    private StoreWithdrawalModel storeWithdrawalModel;

    @ApiOperation("获取账户信息")
    @GetMapping("accountInfo")
    public JsonResult<StoreZjAccountInfoVO> accountInfo(HttpServletRequest request) throws Exception {
        Vendor vendor = UserUtil.getUser(request, Vendor.class);

        StoreOpenAccount storeOpenAccount = storeOpenAccountModel.getStoreOpenAccountByStoreId(vendor.getStoreId());
        AssertUtil.notNull(storeOpenAccount,"未开户");
        AssertUtil.isTrue(!storeOpenAccount.getState().equals(StoreOpenAccountConst.STATE_30),"未签约");

        //查询账户信息
        Tx4691Response tx4691Response = ZjPayUtil.querySellerAccountInfo(vendor.getStoreId().toString(), stringRedisTemplate.opsForValue().get("zj_pay_institution_id"));
        log.debug("查询账户信息响应==================================================================");
        log.debug(JSON.toJSONString(tx4691Response));
        log.debug("==================================================================");
        if (!"2000".equals(tx4691Response.getCode())){
            //请求失败
            log.error("查询账户信息失败：" + tx4691Response.getMessage());
            throw new MallException(tx4691Response.getMessage());
        }

        StoreZjAccountInfoVO vo = new StoreZjAccountInfoVO(storeOpenAccount);
        vo.setBalance(new BigDecimal(tx4691Response.getBalance()).divide(new BigDecimal(100),2, RoundingMode.HALF_UP));

        return SldResponse.success(vo);
    }

    @ApiOperation("获取提现记录列表")
    @GetMapping("list")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "withdrawalSn", value = "提现单号", paramType = "query"),
            @ApiImplicitParam(name = "createTimeStart", value = "申请时间开始", paramType = "query"),
            @ApiImplicitParam(name = "createTimeEnd", value = "申请时间结束", paramType = "query"),
            @ApiImplicitParam(name = "state", value = "状态，10-提现审核中，20提现成功待打款，21-提现失败", paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "分页大小", defaultValue = "20", paramType = "query"),
            @ApiImplicitParam(name = "current", value = "当前页面位置", defaultValue = "1", paramType = "query")
    })
    public JsonResult<PageVO<StoreWithdrawalListVO>> list(HttpServletRequest request, String withdrawalSn, Date createTimeStart, Date createTimeEnd, Integer state) {
        Vendor vendor = UserUtil.getUser(request, Vendor.class);
        PagerInfo pager = WebUtil.handlerPagerInfo(request);

        StoreWithdrawalExample storeWithdrawalExample = new StoreWithdrawalExample();
        storeWithdrawalExample.setWithdrawalSnLike(withdrawalSn);
        storeWithdrawalExample.setCreateTimeAfter(createTimeStart);
        storeWithdrawalExample.setCreateTimeBefore(createTimeEnd);
        storeWithdrawalExample.setState(state);
        storeWithdrawalExample.setStoreId(vendor.getStoreId());
        List<StoreWithdrawal> storeWithdrawalList = storeWithdrawalModel.getStoreWithdrawalList(storeWithdrawalExample, pager);
        List<StoreWithdrawalListVO> vos = new ArrayList<>();
        storeWithdrawalList.forEach(storeWithdrawal -> vos.add(new StoreWithdrawalListVO(storeWithdrawal)));

        return SldResponse.success(new PageVO<>(vos,pager));
    }

    @ApiOperation("提现")
    @PostMapping("withdrawal")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "amount", value = "提现金额", required = true)
    })
    public JsonResult<Object> withdrawal(HttpServletRequest request,
                                         @RequestParam(value = "amount") BigDecimal amount) throws Exception {
        Vendor vendor = UserUtil.getUser(request, Vendor.class);

        StoreOpenAccount storeOpenAccount = storeOpenAccountModel.getStoreOpenAccountByStoreId(vendor.getStoreId());
        AssertUtil.notNull(storeOpenAccount,"未开户");
        AssertUtil.isTrue(!storeOpenAccount.getState().equals(StoreOpenAccountConst.STATE_30),"未签约");
        Tx4643Response tx4643Response = ZjPayUtil.sellerWithdrawal(vendor.getStoreId().toString(), stringRedisTemplate.opsForValue().get("zj_pay_institution_id"), storeOpenAccount.getBindCardSn(), amount);
        log.debug("提现申请响应==================================================================");
        log.debug(JSON.toJSONString(tx4643Response));
        log.debug("==================================================================");
        if (!"2000".equals(tx4643Response.getCode())){
            //请求失败
            log.error(tx4643Response.getTxSN() + "提现申请失败：" + tx4643Response.getMessage());
            throw new MallException(tx4643Response.getMessage());
        }
        String status = tx4643Response.getStatus();//20-处理中，40-失败
        if (!"20".equals(status)){
            log.error(tx4643Response.getTxSN() + "提现申请失败：" + tx4643Response.getResponseMessage());
            throw new MallException(tx4643Response.getResponseMessage());
        }

        //提现日志
        StoreWithdrawal storeWithdrawal = new StoreWithdrawal();
        storeWithdrawal.setStoreId(vendor.getStoreId());
        storeWithdrawal.setVendorId(vendor.getVendorId());
        storeWithdrawal.setWithdrawalSn(tx4643Response.getTxSN());
        storeWithdrawal.setAmount(amount);
        storeWithdrawal.setBankAccountName(storeOpenAccount.getBankAccountName());
        storeWithdrawal.setBankAccountNumber(storeOpenAccount.getBankAccountNumber());
        storeWithdrawal.setBankId(storeOpenAccount.getBankId());
        storeWithdrawal.setBankName(storeOpenAccount.getBankName());
        storeWithdrawal.setBranchName(storeOpenAccount.getBranchName());
        storeWithdrawal.setCreateTime(new Date());
        storeWithdrawal.setState(StoreOpenAccountConst.WITHDRAWAL_STATE_10);
        storeWithdrawalModel.saveStoreWithdrawal(storeWithdrawal);

        return SldResponse.success("操作成功，请静待提现到账。");
    }

    /**
     * 中金开户、绑卡回调
     *
     */
    @PostMapping("callback")
    public void signCallback(HttpServletRequest request, HttpServletResponse response) {
        log.debug("=========================================");
        log.debug("中金签约回调开始");
        log.debug(JSON.toJSONString(request.getParameterMap()));
        log.debug("=========================================");

        try {
            // 1 获得参数message和signature
            String message = request.getParameter("message");
            String signature = request.getParameter("signature");
            String isDgEnv=request.getParameter("isDgEnv");
            String digitalEnvelope=request.getParameter("digitalEnvelope");
            String signAlgorithm=request.getParameter("signAlgorithm");
            String signSN=request.getParameter("signSN");
            String encryptSN=request.getParameter("encryptSN");

            // 2 生成交易结果对象
            NoticeRequest noticeRequest;
            if("YES".equals(isDgEnv)) {
                //数字信封解密验签
                noticeRequest = new NoticeRequest(message, signature,digitalEnvelope,signSN,encryptSN,signAlgorithm);
            }else {
                //非数字信封解密验签
                if(StringUtil.isNotEmpty(signSN)) {
                    message = message +","+signSN+","+signAlgorithm;
                }
                noticeRequest = new NoticeRequest(message, signature);
            }

            Notice4658Request nr = new Notice4658Request(noticeRequest.getDocument());
            log.debug("=========================================");
            log.debug(JSON.toJSONString(nr));
            log.debug("=========================================");

            String sourceTxCode = nr.getSourceTxCode();
            if (!"4643".equals(sourceTxCode)){
                //只处理4643提现，其他不处理
                PrintWriter out = response.getWriter();
                this.response(out);
                out.flush();
                out.close();
                return;
            }

            String sourceTxSN = nr.getSourceTxSN();//提现流水号
            StoreWithdrawal storeWithdrawal = storeWithdrawalModel.getStoreWithdrawalByWithdrawalSn(sourceTxSN);
            if (storeWithdrawal == null){
                //无提现记录
                PrintWriter out = response.getWriter();
                this.response(out);
                out.flush();
                out.close();
                return;
            }

            //更新提现记录
            StoreWithdrawal update = new StoreWithdrawal();
            update.setWithdrawalId(storeWithdrawal.getWithdrawalId());
            if ("30".equals(nr.getStatus())){
                //提现成功
                update.setState(StoreOpenAccountConst.WITHDRAWAL_STATE_20);
            }else {
                update.setState(StoreOpenAccountConst.WITHDRAWAL_STATE_21);
                update.setFailReason(nr.getResponseMessage());
            }
            update.setDealTime(new Date());
            storeWithdrawalModel.updateStoreWithdrawal(update);

            PrintWriter out = response.getWriter();
            this.response(out);
            out.flush();
            out.close();
        }catch (Exception e){
            log.error("中金支付回调异常：" , e);
        }
    }

    /**
     * 给支付平台发送回调成功信息，发送后支付平台不再进行回调
     * @param out 响应
     */
    private void response(PrintWriter out){
        String xmlString = new NoticeResponse().getMessage();
        String base64String = new String(cpcn.institution.tools.util.Base64.encode(xmlString.getBytes(StandardCharsets.UTF_8)));
        out.print(base64String);
    }

}
