package org.jeecg.modules.apiService.impl;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.config.shiro.ShiroRealm;
import org.jeecg.modules.apiBean.PageBean;
import org.jeecg.modules.apiService.AmountService;
import org.jeecg.modules.apiUtils.CommonUtils;
import org.jeecg.modules.hanHaiMember.entity.HanHaiMember;
import org.jeecg.modules.hanHaiMember.service.IHanHaiMemberService;
import org.jeecg.modules.pay.MpWxPayService;
import org.jeecg.modules.teambuyBalanceLog.entity.TeambuyBalanceLog;
import org.jeecg.modules.teambuyBalanceLog.service.ITeambuyBalanceLogService;
import org.jeecg.modules.teambuyBanner.entity.TeambuyBanner;
import org.jeecg.modules.teambuyCash.entity.TeambuyCash;
import org.jeecg.modules.teambuyCash.service.ITeambuyCashService;
import org.jeecg.modules.teambuyCashoutLog.entity.TeambuyCashoutLog;
import org.jeecg.modules.teambuyCashoutLog.service.ITeambuyCashoutLogService;
import org.jeecg.modules.transfer.TransferToUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;

@Slf4j
@Service
public class AmountServiceImpl implements AmountService {
    /******************************************************************************************************************/
    //微信小程序的 AppID
    @Value("${wx.miniapp.appid}")
    private String appid;
    //微信小程序的密钥
    @Value("${wx.miniapp.secret}")
    private String secret;
    //商户号
    @Value("${wx.miniapp.merchantId}")
    private String mchid;
    //商户APIV3密钥
    @Value("${wx.miniapp.apiV3Key}")
    private String apiV3Key;
    //商户API私钥路径
    @Value("${wx.miniapp.privateKeyPath}")
    private String privateKeyFilePath;
    //商户API公钥路径
    @Value("${wx.miniapp.publicKeyPath}")
    private String wechatPayPublicKeyFilePath;
    //商户API公钥ID
    @Value("${wx.miniapp.publicKeyId}")
    private String wechatPayPublicKeyId;
    //商户证书序列号
    @Value("${wx.miniapp.merchantSerialNumber}")
    private String certiticateSerialNo;
    //支付回调地址
    @Value("${wx.miniapp.cashNotifyUrl}")
    private String cashNotifyUrl;

    //支付接口
    @Autowired
    private MpWxPayService mpWxPayService;
    //权限验证
    @Resource
    private ShiroRealm shiroRealm;
    //用户信息
    @Resource
    private IHanHaiMemberService hanHaiMemberService;
    //收支信息
    @Resource
    private ITeambuyBalanceLogService teambuyBalanceLogService;
    //充值提现信息
    @Resource
    private ITeambuyCashService teambuyCashService;
    //提现记录信息
    @Resource
    private ITeambuyCashoutLogService teambuyCashoutLogService;

    /******************************************************************************************************************/

    @Override
    public Result<?> queryCashoutLog(String token, PageBean pageBean) {
        log.info("提现记录列表查询开始");
        //权限验证
        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiOpenId(token);
        //HanHaiMember hanHaiMember = hanHaiMemberService.getById("1919589727643111426");
        //返回信息
        String massege = "";
        //分页信息
        Page<TeambuyCashoutLog> page = null;
        //查询信息
        LambdaQueryChainWrapper<TeambuyCashoutLog> query = null;
        //返回信息
        Page<TeambuyCashoutLog> pageList = null;

        try{
            //分页
            page = new Page<TeambuyCashoutLog>(pageBean.getPageNo(), pageBean.getPageSize());
            query = teambuyCashoutLogService
                    .lambdaQuery();

            //组装查询条件
            query.eq(TeambuyCashoutLog::getUserId, hanHaiMember.getId());

            //按照创建时间降序排列
            query.orderByDesc(TeambuyCashoutLog::getCreateTime);

            //获取轮播图信息
            pageList = query.page(page);

            log.info("提现记录列表查询结束");
            return Result.OK("提现记录列表", pageList);
        }catch (Exception e){
            e.printStackTrace();
            return Result.error("提现记录列表查询失败");
        }
    }

    //提现
    @Override
    public Result<?> cashOut(String token, String userName, BigDecimal transferAmount) {
        log.info("提现申请开始");
        //权限验证
        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiOpenId(token);
        //HanHaiMember hanHaiMember = hanHaiMemberService.getById("1919589727643111426");

        //提现结果
        String massage = "提现申请失败";

        try{
            //0、基础约束
            BigDecimal balance = hanHaiMember.getBalance();//用户余额
            //金额不能为空
            if(null == transferAmount){
                log.info("金额为空，请填写大于0的整数金额");
                return Result.error("金额小于0，请填写大于0的整数金额");
            }
            if(transferAmount.compareTo(balance)>0){
                //提现金额大于余额
                log.info("余额不足，当前余额：{}", balance);
                return Result.error("余额不足");
            }
            //提现金额要为整数
            if(transferAmount.scale()>0){
                log.info("请填写大于0的整数金额，当前输入金额：{}", transferAmount);
                return Result.error("请填写大于0的整数金额");
            }
            //提现金额大于0的整数
            if(transferAmount.compareTo(new BigDecimal(0))<=0){
                log.info("请填写大于0的整数金额，当前输入金额：{}", transferAmount);
                return Result.error("请填写大于0的整数金额");
            }
            if(StringUtils.isEmpty(userName)){
                log.info("用户姓名未填写");
                return Result.error("用户姓名未填写");
            }


            //1.微信提现基础参数
            Map map = getMap();
            //变化的用户信息参数
            map.put("openid", hanHaiMember.getAppletOpenid());//用户openid
            map.put("userName", userName);//用户真实姓名
            map.put("transferAmount", transferAmount);//提现金额, 单位为“分”
            String idStr = "H" + IdWorker.getIdStr();
            map.put("outBillNo", idStr);//商户单号

            TransferToUser client = new TransferToUser(
                    map.get("mchid").toString(),  // 商户号，是由微信支付系统生成并分配给每个商户的唯一标识符，商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756
                    map.get("certiticateSerialNo").toString(), // 商户API证书序列号，如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053
                    map.get("privateKeyFilePath").toString(), // 商户API证书私钥文件路径，本地文件路径
                    map.get("wechatPayPublicKeyId").toString(), // 微信支付公钥ID，如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816
                    map.get("wechatPayPublicKeyFilePath").toString() // 微信支付公钥文件路径，本地文件路径
            );

            //2、场景信息
            TransferToUser.TransferToUserRequest request = new TransferToUser.TransferToUserRequest();
            request.appid = map.get("appid").toString();
            request.outBillNo = map.get("outBillNo").toString();
            request.transferSceneId = map.get("transferSceneId").toString();
            request.openid = map.get("openid").toString();
            request.userName = client.encrypt(map.get("userName").toString());
            request.transferAmount = transferAmount.longValue()*100;//单位为分
            request.transferRemark = map.get("transferRemark").toString();
            request.notifyUrl = map.get("notifyUrl").toString();
            request.userRecvPerception = map.get("userRecvPerception").toString();
            request.transferSceneReportInfos = new ArrayList<>();
            {
                TransferToUser.TransferSceneReportInfo item0 = new TransferToUser.TransferSceneReportInfo();
                item0.infoType = map.get("infoType1").toString();
                item0.infoContent = map.get("infoContent1").toString();
                request.transferSceneReportInfos.add(item0);
                TransferToUser.TransferSceneReportInfo item1 = new TransferToUser.TransferSceneReportInfo();
                item1.infoType = map.get("infoType2").toString();
                item1.infoContent = map.get("infoContent2").toString();
                request.transferSceneReportInfos.add(item1);
            }

            //3、执行提现
            TransferToUser.TransferToUserResponse response = client.run(request, map);
            log.info("提现发起成功，outBillNo："+response.outBillNo + "，transferBillNo：" +response.transferBillNo + "，state：" +response.state+ "，packageInfo：" + response.packageInfo);
            switch (response.state){
                case ACCEPTED:
                    log.info("转账已受理");
                    massage = "转账已受理";
                    break;
                case PROCESSING:
                    log.info("转账锁定资金中。如果一直停留在该状态，建议检查账户余额是否足够，如余额不足，可充值后再原单重试");
                    massage = "转账锁定资金中。如果一直停留在该状态，建议检查账户余额是否足够，如余额不足，可充值后再原单重试";
                    break;
                case WAIT_USER_CONFIRM:
                    log.info("待收款用户确认，可拉起微信收款确认页面进行收款确认");
                    massage = "待收款用户确认，可拉起微信收款确认页面进行收款确认";
                    break;
                case TRANSFERING:
                    log.info("转账中，可拉起微信收款确认页面再次重试确认收款");
                    massage = "转账中，可拉起微信收款确认页面再次重试确认收款";
                    break;
                case SUCCESS:
                    log.info("转账成功");
                    massage = "转账成功";
                    break;
                case FAIL:
                    log.info("转账失败");
                    massage = "转账失败";
                    break;
                case CANCELING:
                    log.info("商户撤销请求受理成功，该笔转账正在撤销中");
                    massage = "商户撤销请求受理成功，该笔转账正在撤销中";
                    break;
                case CANCELLED:
                    log.info("转账撤销完成");
                    massage = "转账撤销完成";
                    break;
            }

            log.info("提现结果：" + massage);

            //4、业务处理
            TeambuyCashoutLog cashoutLog = new TeambuyCashoutLog();
            cashoutLog.setAmount(transferAmount);
            cashoutLog.setRealName(userName);
            cashoutLog.setId(response.outBillNo);
            cashoutLog.setOutBillNo(response.outBillNo);
            cashoutLog.setTransferBillNo(response.transferBillNo);
            cashoutLog.setPackageInfo(response.packageInfo);
            cashoutLog.setUserId(hanHaiMember.getId());
            teambuyCashoutLogService.save(cashoutLog);
            //余额减少
            BigDecimal oldBalance = hanHaiMember.getBalance();
            BigDecimal newBalance = oldBalance.subtract(cashoutLog.getAmount());
            hanHaiMember.setBalance(newBalance);
            hanHaiMemberService.updateById(hanHaiMember);

            //5、返回信息
            log.info("提现申请结束");
            return Result.OK(massage, response);
        }catch (Exception e){
            e.printStackTrace();
            log.info("提现失败：" + e.getMessage());
            return Result.error(e.getMessage());

        }
    }

    //领取提现接口
    @Override
    public Result<?> getMoney(String token,String id){
        log.info("提现金额领取开始");
        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiOpenId(token);

        try{
            TeambuyCashoutLog cashoutLog = teambuyCashoutLogService
                    .lambdaQuery()
                    .eq(TeambuyCashoutLog::getUserId, hanHaiMember.getId())
                    .eq(TeambuyCashoutLog::getId, id)
                    .eq(TeambuyCashoutLog::getStatus, "0")
                    .one();
            if(null != cashoutLog){
                //提现日志记录
                cashoutLog.setStatus("1");
                cashoutLog.setPaymentTime(CommonUtils.getCurrentTime());
                teambuyCashoutLogService.updateById(cashoutLog);

                //收支明细日志记录
                TeambuyBalanceLog balanceLog = new TeambuyBalanceLog();
                balanceLog.setTitle("提现");
                balanceLog.setRecordType("2");//金额提现
                balanceLog.setCashType("1");//支出
                balanceLog.setUserId(hanHaiMember.getId());
                balanceLog.setAmount(cashoutLog.getAmount());
                teambuyBalanceLogService.save(balanceLog);

                log.info("提现金额领取结束");
                return Result.OK("领取提现结束");
            }else {
                log.info("提现内容不存在，请检查提现记录：{}", id);
                return Result.error("提现内容不存在，请检查提现记录id：" + id);
            }
        }catch (Exception e){
            e.printStackTrace();
            log.info("领取提现失败:{}", e.getMessage());
            return Result.OK("领取提现失败");
        }
    }

    //充值
    @Override
    public Result<?> cashIn(String token, TeambuyCash teambuyCash) {
        //权限验证
        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiOpenId(token);
        try{
            //订单信息
            String payNo = IdWorker.getIdStr();//生成订单号
            teambuyCash.setId(payNo);//订单编号
            teambuyCash.setTitle("金额充值");//订单名称
            teambuyCash.setType("0");//类型为充值
            teambuyCash.setUserId(hanHaiMember.getId());//关联用户

            //创建订单信息
            teambuyCashService.save(teambuyCash);

            //吊起微信支付
            BigDecimal price = teambuyCash.getAmount();//价格
            String productName = teambuyCash.getTitle();//服务名称

            String s = price.multiply(new BigDecimal(100)).toString();
            int i1 = Double.valueOf(s).intValue();
            Object appOrder = mpWxPayService.createOrder(
                    "充值"+ productName ,
                    "127.0.0.1",
                    teambuyCash.getId(),
                    i1,
                    teambuyCash.getId(),
                    hanHaiMember.getAppletOpenid(),
                    teambuyCash.toString(),
                    cashNotifyUrl);
            return Result.OK("充值成功",appOrder);
        }catch (Exception e){
            e.printStackTrace();
            return Result.error("充值失败");
        }
    }

    @Override
    public Result<?> queryAmountLog(String token, TeambuyBalanceLog balanceLog, PageBean pageBean) {
        //权限验证
        HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiOpenId(token);
        //返回信息
        String massege = "";
        //分页信息
        Page<TeambuyBalanceLog> page = null;
        //查询信息
        LambdaQueryChainWrapper<TeambuyBalanceLog> query = null;
        //返回信息
        Page<TeambuyBalanceLog> pageList = null;

        try{
            //分页
            page = new Page<TeambuyBalanceLog>(pageBean.getPageNo(), pageBean.getPageSize());
            query = teambuyBalanceLogService
                    .lambdaQuery();

            //收支关联者
            query.eq(TeambuyBalanceLog::getUserId, hanHaiMember.getId());

            //收支类型
            if(StringUtils.isNotBlank(balanceLog.getCashType())){
                query.eq(TeambuyBalanceLog::getCashType, balanceLog.getCashType());
            }
            //记录类型
            if(StringUtils.isNotBlank(balanceLog.getRecordType())){
                query.eq(TeambuyBalanceLog::getRecordType, balanceLog.getRecordType());
            }

            //按照排序编号降序排列
            query.orderByDesc(TeambuyBalanceLog::getCreateTime);

            //获取商品信息信息
            pageList = query.page(page);

            return Result.OK("收支列表", pageList);
        }catch (Exception e){
            e.printStackTrace();
            return Result.error("收支列表查询失败");
        }
    }

    //充值回调
    public Result<?> CashNotify(String requestBody){
        WxPayOrderNotifyResult notify = mpWxPayService.notify(requestBody);
        String outTradeNo = notify.getOutTradeNo();
        log.info("充值回调订单号码："+outTradeNo);

        try{

            //查询订单信息
            TeambuyCash teambuyCash = teambuyCashService.getById(outTradeNo);
            //如果订单存在则修改订单状态
            if (null != teambuyCash){
                if("0".equals(teambuyCash.getStatus())){
                    teambuyCash.setStatus("1");//订单状态
                    teambuyCash.setPayTime(CommonUtils.getCurrentTime());//订单支付时间
                    teambuyCashService.updateById(teambuyCash);

                    //用户余额修改
                    HanHaiMember hanHaiMember = hanHaiMemberService.getById(teambuyCash.getUserId());
                    BigDecimal balance = hanHaiMember.getBalance().add(teambuyCash.getAmount());
                    hanHaiMember.setBalance(balance);
                    hanHaiMemberService.updateById(hanHaiMember);

                    //添加充值日志
                    TeambuyBalanceLog balanceLog = new TeambuyBalanceLog();
                    balanceLog.setAmount(teambuyCash.getAmount());//充值金额
                    balanceLog.setCashType("0");//收入
                    balanceLog.setRecordType("1");//余额充值
                    balanceLog.setUserId(teambuyCash.getUserId());
                    balanceLog.setTitle("余额充值");
                    teambuyBalanceLogService.save(balanceLog);
                }
            }

        }catch (Exception e){
            log.info("充值回调失败，订单号码："+outTradeNo);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 微信提现基础参数
     * @return
     */
    public Map getMap(){
        Map<String, Object> map = new HashedMap();//转账接口所需参数
        map.put("host", "https://api.mch.weixin.qq.com");//请求地址
        map.put("method", "POST");//请求类型
        map.put("path", "/v3/fund-app/mch-transfer/transfer-bills");//提现接口
        map.put("notifyUrl", "https://www.yurangongfang.com/massage-admin/massage/cash/cashoutNotify/");//回调接口

        //微信商户参数
//        map.put("appid", "wx77ba4c7131677a74");//小程序appid
//        map.put("mchid", "1712378227");//商户号
//        map.put("certiticateSerialNo", "33E9FE8076531A7C7AD401DC34E053DBD7C28E22");//商户序列号
//        map.put("privateKeyFilePath", "jeecg-boot-module-system/src/main/resources/apiclient_key.pem");//商户私钥证书
//        map.put("wechatPayPublicKeyId", "PUB_KEY_ID_0117123782272025033100396400002931");//商户公钥id
//        map.put("wechatPayPublicKeyFilePath", "jeecg-boot-module-system/src/main/resources/pub_key.pem");//商户公钥证书
        map.put("appid", appid);//小程序appid
        map.put("mchid", mchid);//商户号
        map.put("certiticateSerialNo", certiticateSerialNo);//商户序列号
        map.put("privateKeyFilePath", privateKeyFilePath);//商户私钥证书
        map.put("wechatPayPublicKeyId", wechatPayPublicKeyId);//商户公钥id
        map.put("wechatPayPublicKeyFilePath", wechatPayPublicKeyFilePath);//商户公钥证书
        map.put("transferSceneId", "1005");//商户转账场景ID 1005-佣金报酬
        map.put("transferRemark", "佣金报酬");//商户转账场景ID 1005-佣金报酬
        map.put("userRecvPerception", "劳务报酬");//商户转账场景ID 1005-佣金报酬


        //变化的用户信息参数
//        map.put("openid", "oFzrW4migndUepy7zYgYO2YoZ5to");//用户openid
//        map.put("userName", "唐斌");//用户真实姓名
//        map.put("transferAmount", 100L);//提现金额, 单位为“分”
//        String idStr = "H" + IdWorker.getIdStr();
//        map.put("outBillNo", idStr);//商户单号


        //转账场景报备信息，ransfer_scene_report_infos为数组类型参数，在现金营销的转账场景下需固定传两条明细，每条“转账场景报备信息明细”包含info_type、info_content两个参数。
        map.put("infoType1","岗位类型");
        map.put("infoContent1","外卖员");
        map.put("infoType2","报酬说明");
        map.put("infoContent2","高温补贴");

        return map;

    }

    //提现回调
    @Override
    public Object cashoutNotify(String signature, String timestamp, String nonce, String serial, String requestBody) {
        log.info("测试提现回调");

        return Result.OK("测试回调");
    }


}
