package com.czg.service.order.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import com.czg.PayCst;
import com.czg.account.dto.shopuser.ShopUserMoneyEditDTO;
import com.czg.account.entity.*;
import com.czg.account.service.*;
import com.czg.constants.PayTypeConstants;
import com.czg.enums.CzgPayEnum;
import com.czg.enums.ShopUserFlowBizEnum;
import com.czg.exception.CzgException;
import com.czg.market.dto.MemberOrderDTO;
import com.czg.market.entity.MemberOrder;
import com.czg.market.entity.MkShopCouponRecord;
import com.czg.market.service.MemberOrderService;
import com.czg.market.service.MkShopCouponRecordService;
import com.czg.market.service.MkShopRechargeService;
import com.czg.market.vo.MkShopRechargeVO;
import com.czg.order.dto.CheckOrderPay;
import com.czg.order.dto.LtPayOtherDTO;
import com.czg.order.entity.OrderInfo;
import com.czg.order.entity.OrderPayment;
import com.czg.order.service.OrderInfoCustomService;
import com.czg.order.service.OrderPaymentService;
import com.czg.pay.CzgPayBaseReq;
import com.czg.pay.CzgRefundReq;
import com.czg.pay.RefundRespDTO;
import com.czg.resp.CzgResult;
import com.czg.service.order.dto.VipMemberPayParamDTO;
import com.czg.service.order.dto.VipPayParamDTO;
import com.czg.service.order.dto.VipRefundDTO;
import com.czg.service.order.service.PayService;
import com.czg.service.order.service.ShopUserPayService;
import com.czg.utils.AssertUtil;
import com.czg.utils.CzgRandomUtils;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ww
 */
@Service
public class ShopUserServiceImpl implements ShopUserPayService {
    @Resource
    private PayService payService;

    @DubboReference
    private ShopUserService shopUserService;
    @DubboReference
    private UserInfoService userInfoService;
    @DubboReference
    private ShopInfoService shopInfoService;
    @DubboReference
    private FreeDineConfigService freeConfigService;
    @Resource
    private OrderInfoCustomService orderInfoCustomService;
    @DubboReference
    private MemberOrderService memberOrderService;
    @Resource
    private MkShopRechargeService shopRechargeService;
    @DubboReference
    private ShopUserFlowService userFlowService;
    @Resource
    private MkShopCouponRecordService recordService;
    @Resource
    private OrderPaymentService paymentService;

    /**
     * 会员充值 校验
     *
     * @return 是否是霸王餐充值
     */
    private boolean checkPayVip(VipPayParamDTO payParam) {
        if (payParam.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new CzgException("充值金额不正确");
        }
        if (payParam.getOrderId() != null) {
            FreeDineConfig freeConfig = freeConfigService.getById(shopInfoService.getMainIdByShopId(payParam.getShopId()));
            AssertUtil.isNull(freeConfig, "该店铺未启用霸王餐");
            if (!freeConfig.getEnable()) {
                throw new CzgException("该店铺未启用霸王餐");
            }
            CheckOrderPay checkOrderPay = payParam.getCheckOrderPay();
            OrderInfo orderInfo = orderInfoCustomService.checkOrderPay(checkOrderPay.setFreeDine(true).setWithCoupon(freeConfig.getWithCoupon()).setWithPoints(freeConfig.getWithPoints()));
            payParam.setAmount(orderInfo.getOrderAmount().multiply(BigDecimal.valueOf(freeConfig.getRechargeTimes())));
            return true;
        }
        return false;
    }

    @Override
    @Transactional
    public CzgResult<Object> cashPayVip(VipPayParamDTO payParam) {
        ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
        AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
        ShopInfo shopInfo = shopInfoService.getById(payParam.getShopId());
        AssertUtil.isNull(shopInfo, "店铺不存在");
        if (shopInfo.getIsMemberInPwd().equals(1)) {
            AssertUtil.isBlank(shopInfo.getOperationPwd(), "请设置操作密码后使用");
            AssertUtil.isBlank(payParam.getPwd(), "请输入操作密码后充值");
            if (!shopInfo.getOperationPwd().equals(SecureUtil.md5(payParam.getPwd()))) {
                return CzgResult.failure("支付密码错误");
            }
        }
        shopRechargeService.recharge(shopUser.getMainShopId(), shopUser.getId(), payParam.getRechargeDetailId(),
                payParam.getAmount(), null, "cash", LocalDateTime.now(),
                ShopUserFlowBizEnum.CASH_IN, true, payParam.getOperator());
        return CzgResult.success();
    }

    @Override
    @Transactional
    public CzgResult<Map<String, Object>> jsPayVip(String clintIp, VipPayParamDTO payParam) {
        boolean isFree = checkPayVip(payParam);
        ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
        AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
        AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
        AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");
        String payOrderNo = payParam.getPlatformType() + CzgRandomUtils.snowflake();
        String payType = isFree ? PayTypeConstants.SourceType.FREE : PayTypeConstants.SourceType.MEMBER_IN;
        payService.initPayment(OrderPayment.pay(payParam.getShopId(), shopUser.getId(), payType, payOrderNo,
                payParam.getAmount(), "", isFree ? payParam.getOrderId() : payParam.getActivateId()));
        return payService.pay(payParam.getShopId(), CzgPayEnum.JS_PAY,
                CzgPayBaseReq.jsPayReq(payOrderNo, "会员充值", payParam.getAmount().multiply(PayService.MONEY_RATE).longValue(),
                        payParam.getPayType(), payParam.getOpenId(), clintIp));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CzgResult<Map<String, Object>> ltPayMember(String clientIp, VipMemberPayParamDTO payParam) {
        ShopUser shopUser = shopUserService.getOne(new QueryWrapper().eq(ShopUser::getMainShopId, shopInfoService.getMainIdByShopId(payParam.getShopId())).eq(ShopUser::getId, payParam.getShopUserId()));
        AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
        MemberOrder memberOrder = memberOrderService.createMemberOrder(new MemberOrderDTO().setName(payParam.getName())
                .setNum(1).setNickName(payParam.getNickName()).setOrderType(payParam.getOrderType())
                .setPlatformType(payParam.getPlatformType()).setSex(payParam.getSex()).setUserId(shopUser.getUserId())
                .setShopId(payParam.getShopId()).setBirthDay(payParam.getBirthDay()));
        AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
        AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");

        LtPayOtherDTO payParam1 = new LtPayOtherDTO()
                .setOpenId(payParam.getOpenId())
                .setPayType(payParam.getPayType())
                .setShopId(payParam.getShopId())
                .setRecordId(shopUser.getId())
                .setPrice(memberOrder.getAmount())
                .setIp(clientIp);
        payParam1.setRelatedId(memberOrder.getId());
        return payService.ltPayOther(payParam1, PayTypeConstants.SourceType.MEMBER_PAY, "会员充值");
    }

    @Override
    @Transactional
    public CzgResult<Map<String, Object>> ltPayVip(String clintIp, VipPayParamDTO payParam) {
        // 霸王餐校验
        boolean isFree = checkPayVip(payParam);
        ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
        AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
        AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
        AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");

        MkShopRechargeVO rechargeVO = shopRechargeService.detail(payParam.getShopId());
        if (payParam.getRechargeDetailId() == null && rechargeVO.getIsCustom() == 0) {
            throw new CzgException("未开启自定义充值金额");
        }
        Long mainShopId = shopInfoService.getMainIdByShopId(payParam.getShopId());
        if (isFree) {
            BigDecimal amount = shopRechargeService.checkRecharge(mainShopId, payParam.getShopId(), shopUser.getUserId(), payParam.getRechargeDetailId(), payParam.getAmount());
            payParam.setAmount(amount);
        }

        String payType = isFree ? PayTypeConstants.SourceType.FREE : PayTypeConstants.SourceType.MEMBER_IN;
        LtPayOtherDTO payParam1 = new LtPayOtherDTO()
                .setOpenId(payParam.getOpenId())
                .setPayType(payParam.getPayType())
                .setShopId(payParam.getShopId())
                .setRecordId(shopUser.getId())
                .setPrice(payParam.getAmount())
                .setIp(clintIp);
        payParam1.setRelatedId(isFree ? payParam.getOrderId() : payParam.getRechargeDetailId());
        return payService.ltPayOther(payParam1, payType, "会员充值");
    }

    @Override
    public CzgResult<Map<String, Object>> recharge(String clientIp, VipPayParamDTO rechargeDTO, Long shopUserId) {
        boolean isFree = checkPayVip(rechargeDTO);
        Long mainShopId = shopInfoService.getMainIdByShopId(rechargeDTO.getShopId());

        ShopUser shopUser = shopUserService.getOne(new QueryWrapper().eq(ShopUser::getMainShopId, mainShopId)
                .eq(ShopUser::getId, shopUserId));
        AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
        MkShopRechargeVO rechargeVO = shopRechargeService.detail(rechargeDTO.getShopId());
        if (rechargeDTO.getRechargeDetailId() == null && rechargeVO.getIsCustom() == 0) {
            throw new CzgException("未开启自定义充值金额");
        }
        UserInfo userInfo = userInfoService.getById(shopUser.getUserId());
        BigDecimal amount = shopRechargeService.checkRecharge(mainShopId, rechargeDTO.getShopId(), shopUser.getUserId(), rechargeDTO.getRechargeDetailId(), rechargeDTO.getAmount());
        String payType = isFree ? PayTypeConstants.SourceType.FREE : PayTypeConstants.SourceType.MEMBER_IN;

        LtPayOtherDTO payParam = new LtPayOtherDTO()
                .setOpenId(PayCst.Type.WECHAT.equals(rechargeDTO.getPayType()) ? userInfo.getWechatOpenId() : userInfo.getAlipayOpenId())
                .setPayType(rechargeDTO.getPayType())
                .setShopId(rechargeDTO.getShopId())
                .setRecordId(shopUser.getId())
                .setPrice(amount)
                .setIp(clientIp);
        payParam.setRelatedId(isFree ? rechargeDTO.getOrderId() : rechargeDTO.getRechargeDetailId());
        return payService.ltPayOther(payParam, payType, "会员充值");
    }

    @Override
    @Transactional
    public CzgResult<Map<String, Object>> scanPayVip(String clintIp, VipPayParamDTO payParam) {
        boolean isFree = checkPayVip(payParam);
        ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
        AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
        String payOrderNo = payParam.getPlatformType() + CzgRandomUtils.snowflake();
        String payType = isFree ? PayTypeConstants.SourceType.FREE : PayTypeConstants.SourceType.MEMBER_IN;
        payService.initPayment(OrderPayment.pay(payParam.getShopId(), shopUser.getId(), payType, payOrderNo,
                payParam.getAmount(), "", isFree ? payParam.getOrderId() : payParam.getActivateId()));
        return payService.pay(payParam.getShopId(), CzgPayEnum.SCAN_PAY,
                CzgPayBaseReq.scanPayReq(payOrderNo, "会员充值", payParam.getAmount().multiply(PayService.MONEY_RATE).longValue(), clintIp));
    }

    @Override
    @Transactional
    public CzgResult<Map<String, Object>> microPayVip(VipPayParamDTO payParam) {
        boolean isFree = checkPayVip(payParam);
        AssertUtil.isBlank(payParam.getAuthCode(), "扫描码不能为空");
        ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
        AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
        String payOrderNo = payParam.getPlatformType() + CzgRandomUtils.snowflake();
        String payType = isFree ? PayTypeConstants.SourceType.FREE : PayTypeConstants.SourceType.MEMBER_IN;
        payService.initPayment(OrderPayment.pay(payParam.getShopId(), shopUser.getId(), payType, payOrderNo, payParam.getAmount(), "", isFree ? payParam.getOrderId() : payParam.getActivateId()));
        CzgResult<Map<String, Object>> mapCzgResult = payService.pay(payParam.getShopId(), CzgPayEnum.MICRO_PAY,
                CzgPayBaseReq.microPay(payOrderNo, "会员充值", payParam.getAmount().multiply(PayService.MONEY_RATE).longValue(), payParam.getAuthCode()));
        mapCzgResult.setData(Map.of("payOrderNo", payOrderNo));
        return mapCzgResult;
    }


    @Override
    public CzgResult<Map<String, BigDecimal>> refundVipBefore(VipRefundDTO payParam) {
        Map<String, BigDecimal> resultMap = new HashMap<>(5);
        ShopUser shopUser = shopUserService.getShopUserInfo(payParam.getShopId(), payParam.getUserId());
        AssertUtil.isNull(shopUser, "该店铺用户不存在");
        ShopUserFlow inFlow = userFlowService.getById(payParam.getFlowId());
        AssertUtil.isNull(inFlow, "充值记录不存在");
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq(ShopUserFlow::getRelationId, payParam.getFlowId());
        queryWrapper.eq(ShopUserFlow::getBizCode, ShopUserFlowBizEnum.AWARD_IN.getCode());
        ShopUserFlow giftFlow = userFlowService.getOne(queryWrapper);
        resultMap.put("amount", shopUser.getAmount());
        resultMap.put("inAmount", inFlow.getAmount());
        resultMap.put("inRefundAmount", inFlow.getRefundAmount());
        resultMap.put("giftAmount", giftFlow == null ? BigDecimal.ZERO : giftFlow.getAmount());
        resultMap.put("giftRefundAmount", giftFlow == null ? BigDecimal.ZERO : giftFlow.getRefundAmount());
        return CzgResult.success(resultMap);
    }

    @Override
    @Transactional
    public CzgResult<Object> refundVip(VipRefundDTO refPayParam) {
        ShopInfo shopInfo = shopInfoService.getById(refPayParam.getShopId());
        if (shopInfo.getIsReturnPwd().equals(1)) {
            AssertUtil.isBlank(shopInfo.getOperationPwd(), "请设置操作密码后使用");
            if (!SecureUtil.md5(refPayParam.getPwd()).equals(shopInfo.getOperationPwd())) {
                throw new CzgException("操作密码错误");
            }
        }
        ShopUser shopUser = shopUserService.getShopUserInfo(refPayParam.getShopId(), refPayParam.getUserId());
        ShopUserFlow inFlow = userFlowService.getById(refPayParam.getFlowId());
        AssertUtil.isNull(inFlow, "充值记录不存在");
        if ("cashIn".equals(inFlow.getBizCode()) || "adminIn".equals(inFlow.getBizCode())) {
            refPayParam.setCashRefund(true);
        }
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq(ShopUserFlow::getRelationId, refPayParam.getFlowId());
        queryWrapper.eq(ShopUserFlow::getBizCode, ShopUserFlowBizEnum.AWARD_IN.getCode());
        ShopUserFlow giftFlow = userFlowService.getOne(queryWrapper);
        if ((inFlow.getAmount().subtract(inFlow.getRefundAmount())).compareTo(refPayParam.getRefAmount()) < 0) {
            return CzgResult.failure("退款失败，退款金额不可大于可退金额");
        }
        //用户余额减去赠送金额 小于 退款金额 则需要勾选 超额退款
        if (giftFlow != null) {
            if (shopUser.getAmount().subtract(giftFlow.getAmount().subtract(giftFlow.getRefundAmount())).compareTo(refPayParam.getRefAmount()) < 0 && !refPayParam.isOutOfRange()) {
                return CzgResult.failure("超额退款,请勾选 超额退款后重试");
            }
        } else {
            if (shopUser.getAmount().compareTo(refPayParam.getRefAmount()) < 0 && !refPayParam.isOutOfRange()) {
                return CzgResult.failure("超额退款,请勾选 超额退款后重试");
            }
        }
        Long refPaymentId = null;
        if (!refPayParam.isCashRefund()) {
            OrderPayment payment;
            if (inFlow.getRelationId() != null) {
                payment = paymentService.getById(inFlow.getRelationId());
            } else {
                return CzgResult.failure("退款失败,该充值记录不存在");
            }
            String refPayOrderNo = "REFVIP" + IdUtil.getSnowflakeNextId();
            refPaymentId = payService.initPayment(OrderPayment.refund(payment.getChannel(), refPayParam.getShopId(), shopUser.getId(), PayTypeConstants.SourceType.MEMBER_IN,
                    refPayOrderNo, refPayParam.getRefAmount(), inFlow.getId(), payment.getPlatformType()));
            CzgResult<RefundRespDTO> refund = payService.refund(refPayParam.getShopId(), new CzgRefundReq(refPayOrderNo, refPayParam.getRemark(),
                    refPayParam.getRefAmount().multiply(PayService.MONEY_RATE).longValue(), payment.getAmount().multiply(PayService.MONEY_RATE).longValue(),
                    payment.getOrderNo(), "", payment.getPlatformType()));
            if (refund.getCode() != 200 || refund.getData() == null || !"SUCCESS".equals(refund.getData().getStatus())) {
                throw new CzgException(refund.getMsg());
            } else {
                paymentService.updateChain()
                        .eq(OrderPayment::getId, refPaymentId)
                        .set(OrderPayment::getPayTime, refund.getData().getRefundTime())
                        .set(OrderPayment::getTradeNumber, refund.getData().getThirdRefundNo())
                        .set(OrderPayment::getPayStatus, PayTypeConstants.PayStatus.SUCCESS)
                        .set(OrderPayment::getRespJson, refund.getData().getOriginalData())
                        .update();
            }
        }
        ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
                .setId(shopUser.getId())
                .setMoney(refPayParam.getRefAmount())
                .setType(0)
                .setRemark("退款")
                .setBizEnum(refPayParam.isCashRefund() ? ShopUserFlowBizEnum.RECHARGE_CASH_REFUND : ShopUserFlowBizEnum.RECHARGE_REFUND)
                .setRelationId(refPaymentId)
                .setRechargeId(inFlow.getId());
        //更新会员余额 并生成流水
        shopUserService.updateMoney(shopUserMoneyEditDTO);
        userFlowService.updateRefund(inFlow.getId(), refPayParam.getRefAmount());
        if (giftFlow != null && (giftFlow.getAmount().subtract(giftFlow.getRefundAmount())).compareTo(BigDecimal.ZERO) > 0) {
            ShopUserMoneyEditDTO giftFlowEdit = new ShopUserMoneyEditDTO()
                    .setId(shopUser.getId())
                    .setMoney(giftFlow.getAmount())
                    .setType(0)
                    .setRemark("退款")
                    .setBizEnum(ShopUserFlowBizEnum.RECHARGE_REFUND)
                    .setRelationId(refPaymentId)
                    .setRechargeId(giftFlow.getId());
            //更新会员余额 并生成流水
            shopUserService.updateMoney(giftFlowEdit);
            userFlowService.updateRefund(giftFlow.getId(), giftFlow.getAmount());
        }
        //移除优惠券
        recordService.remove(QueryWrapper.create()
                .eq(MkShopCouponRecord::getSourceFlowId, inFlow.getId())
                .eq(MkShopCouponRecord::getSource, "activate")
                .eq(MkShopCouponRecord::getStatus, 0));
        return CzgResult.success();
    }

}
