package com.zhongshu.card.server.core.service.pay;

import com.github.microservice.core.util.JsonUtil;
import com.github.microservice.core.util.bean.BeanUtil;
import com.github.microservice.pay.client.model.PayProductParameter;
import com.github.microservice.pay.client.model.ledger.GeneralLedgerQueryModel;
import com.github.microservice.pay.client.model.ledger.TransactionLogModel;
import com.github.microservice.pay.client.model.ledger.TransferTransactionsModel;
import com.github.microservice.pay.client.model.weChatMiniApp.WeChatMiniAppPayRet;
import com.github.microservice.pay.client.ret.ResultContent;
import com.github.microservice.pay.client.ret.ResultState;
import com.github.microservice.pay.client.service.ledger.GeneralLedgerService;
import com.github.microservice.pay.client.service.ledger.TransactionLogService;
import com.github.microservice.pay.client.service.product.MiniAppPayService;
import com.github.microservice.pay.client.type.ledger.TransactionStatus;
import com.github.microservice.pay.client.type.ledger.TransactionType;
import com.github.microservice.types.payment.PaymentChannelType;
import com.github.microservice.types.payment.PaymentType;
import com.zhongshu.card.client.model.mqtt.SendMessageModel;
import com.zhongshu.card.client.model.pay.QueryRechargeOrderModel;
import com.zhongshu.card.client.model.pay.QueryRechargeParam;
import com.zhongshu.card.client.model.pay.RechargeOrderModel;
import com.zhongshu.card.client.model.pay.RechargeParam;
import com.zhongshu.card.client.model.wechat.MiniAppUserInfoVo;
import com.zhongshu.card.client.type.payAccount.RechargeOrderStatus;
import com.zhongshu.card.client.utils.DateUtils;
import com.zhongshu.card.server.core.dao.pay.BalanceRechargeOrderDao;
import com.zhongshu.card.server.core.domain.pay.BalanceRechargeOrder;
import com.zhongshu.card.server.core.domain.pay.PayAccount;
import com.zhongshu.card.server.core.service.base.SuperService;
import com.zhongshu.card.server.core.service.mqtt.MqttServiceImpl;
import com.zhongshu.card.server.core.service.paySetting.OrgPayAccountService;
import com.zhongshu.card.server.core.service.paySetting.ProjectPaySettingServiceImpl;
import com.zhongshu.card.server.core.util.BeanUtils;
import com.zhongshu.card.server.core.util.CommonUtil;
import com.zhongshu.card.server.core.util.wx.WechatCUtil;
import io.netty.util.internal.StringUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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.List;
import java.util.Map;

@Service
@Slf4j
public class BalancePayService extends SuperService {

    @Autowired
    PayAccountService payAccountService;

    @Autowired
    MiniAppPayService miniAppPayService;

    @Autowired
    BalanceRechargeOrderDao rechargeOrderDao;

    @Autowired
    OrgPayAccountService orgPayAccountService;

    @Autowired
    ProjectPaySettingServiceImpl projectPaySettingService;

    @Autowired
    TransactionLogService transactionLogService;

    @Autowired
    GeneralLedgerService generalLedgerService;

    @Autowired
    MqttServiceImpl mqttService;

    @Autowired
    WechatCUtil wechatCUtil;


    /**
     * 下单并生成调用支付参数
     */
    @Transactional
    public Object recharge(RechargeParam param) {
        String projectOid = getCurrentProjectOid();
        String userId = getCurrentUserId();
        String appId = getCurrentAppId();

        if (StringUtils.isBlank(projectOid)){
            return com.github.microservice.net.ResultContent.buildFail("获取项目id失败");
        }

        param.setProjectOid(projectOid);
        param.setUserId(userId);
        param.setAppid(appId);

        //根据项目id和支付渠道获取支付账户名
        String accountName = orgPayAccountService.queryOgPayAccount(param.getProjectOid(), param.getPaymentType());
        ;
        //生成订单id
        String orderNo = CommonUtil.UUID();
        //调用小程序支付
        PayProductParameter<Object> payProductParameter = new PayProductParameter<>();
        param.setOrderNo(orderNo);
        Map<String, Object> meta = BeanUtil.bean2Map(param);
        payProductParameter.setMeta(meta);
        payProductParameter.setAccountName(accountName);
        ResultContent<Object> prepay = miniAppPayService.prepay(payProductParameter);
        if (!prepay.getState().equals(ResultState.Success)) {
            return prepay;
        }
        PayAccount payAccount = payAccountService.getUserChildren(param.getProjectOid(), param.getUserId(), param.getPaymentType().getChannelType());
        //创建订单
        BalanceRechargeOrder balanceRechargeOrder = new BalanceRechargeOrder();
        balanceRechargeOrder.setProjectOid(param.getProjectOid());
        balanceRechargeOrder.setUserId(param.getUserId());
        balanceRechargeOrder.setPaymentType(param.getPaymentType());
        balanceRechargeOrder.setPayAccount(payAccount.getId());
        balanceRechargeOrder.setStatus(RechargeOrderStatus.Wait);
        balanceRechargeOrder.setOrderNo(orderNo);
        balanceRechargeOrder.setTotal(new BigDecimal(param.getTotal()));
        balanceRechargeOrder.setPrepay(prepay.getContent());
        balanceRechargeOrder.setDescription(param.getDescription());
//        balanceRechargeOrder.setOid(param.getOid());
        rechargeOrderDao.save(balanceRechargeOrder);
        return ResultContent.buildContent(toModel(balanceRechargeOrder));
    }

    public void handleWeChatCallback(WeChatMiniAppPayRet ret) {
        log.info("收到的消息：{}", JsonUtil.toJson(ret));
        BalanceRechargeOrder rechargeOrder = rechargeOrderDao.findTopByOrderNo(ret.getOutTradeNo());
        if (!rechargeOrder.getStatus().equals(RechargeOrderStatus.Wait)){
            return;
        }
        switch (ret.getTradeState()) {
            case "SUCCESS" -> {
                log.info("收到的消息Success：{}", JsonUtil.toJson(ret));
                rechargeOrder.setStatus(RechargeOrderStatus.Success);
                //获取项目总账户
                PayAccount projectPayAccount = payAccountService.getProjectParent(rechargeOrder.getProjectOid());
                //获取用户余额支付子账
                PayAccount userPayAccount = payAccountService.getUserChildren(rechargeOrder.getProjectOid(), rechargeOrder.getUserId(), rechargeOrder.getPaymentType().getChannelType());
                //构建转账参数
                TransferTransactionsModel transferModel = new TransferTransactionsModel();
                //构建出账账户
                TransferTransactionsModel.GeneralLedgerTransaction sourceTransaction = new TransferTransactionsModel.GeneralLedgerTransaction();
                sourceTransaction.setGeneralLedgerId(projectPayAccount.getLedgerId());
                sourceTransaction.setOrderNumber(rechargeOrder.getOrderNo());
                sourceTransaction.setTransactionType(TransactionType.Deposit);
                sourceTransaction.setTransactionStatus(TransactionStatus.Success);
                sourceTransaction.setAmount(rechargeOrder.getTotal().negate().longValue());
                sourceTransaction.setRemark("用户余额充值");
                sourceTransaction.setMeta(Map.of("paymentType",PaymentType.WeChat, "description","用户充值", "summary", "用户充值"));
                transferModel.setSource(new TransferTransactionsModel.GeneralLedgerTransaction[]{sourceTransaction});

                //构建入账账户
                TransferTransactionsModel.GeneralLedgerTransaction destinationTransaction = new TransferTransactionsModel.GeneralLedgerTransaction();
                destinationTransaction.setGeneralLedgerId(userPayAccount.getLedgerId());
                destinationTransaction.setOrderNumber(rechargeOrder.getOrderNo());
                destinationTransaction.setTransactionType(TransactionType.Deposit);
                destinationTransaction.setTransactionStatus(TransactionStatus.Success);
                destinationTransaction.setAmount(rechargeOrder.getTotal().longValue());
                destinationTransaction.setRemark("用户余额充值");
                destinationTransaction.setMeta(Map.of("paymentType",PaymentType.WeChat, "description","用户充值", "summary", "用户充值"));
                transferModel.setDestinations(new TransferTransactionsModel.GeneralLedgerTransaction[]{destinationTransaction});
                //发起转账
                ResultContent<List<TransactionLogModel>> transfer = transactionLogService.transfer(transferModel);
                if (transfer.getState().equals(ResultState.Success)) {
                    //处理订单状态
                    rechargeOrder.setStatus(RechargeOrderStatus.Success);
                    // 发送成功通知消息
                    SendMessageModel sendMessageModel = new SendMessageModel();
                    sendMessageModel.setMessage(JsonUtil.toJson(Map.of("status", RechargeOrderStatus.Success.name(), "orderNo", rechargeOrder.getOrderNo())));
                    String userId = rechargeOrder.getUserId();
                    String topic = String.format("/wechat/pay/%s", userId);
                    sendMessageModel.setTopic(topic);
                    sendMessageModel.setUserId(userId);
                    log.info("mq topic : {}", topic);
                    mqttService.sendMessage(sendMessageModel);
                }
            }
            case "PAYERROR", "REFUND" -> {
                rechargeOrder.setStatus(RechargeOrderStatus.Fail);
                rechargeOrder.setStatusDesc(ret.getTradeStateDesc());
            }
            case "CLOSED" -> {
                rechargeOrder.setStatus(RechargeOrderStatus.Cancel);
                rechargeOrder.setStatusDesc(rechargeOrder.getStatusDesc());
            }
        }
        rechargeOrderDao.save(rechargeOrder);
    }

    public ResultContent balancePay(String projectOid, String oid, String userId, BigDecimal total, String orderNo, String remark) {
        //获取用户余额支付子账户
        PayAccount userBalancePayment = payAccountService.getUserChildren(projectOid, userId, PaymentChannelType.BalancePayment);
        //获取机构待结算账户
        PayAccount orgWaitSettle = payAccountService.getOrgChildren(projectOid, oid, PaymentChannelType.WaitSettle);
        //支付：用户余额子账- 项目待结算子账+
        //构建转账参数
        TransferTransactionsModel transferModel = new TransferTransactionsModel();
        //构建出账账户
        TransferTransactionsModel.GeneralLedgerTransaction sourceTransaction = new TransferTransactionsModel.GeneralLedgerTransaction();
        sourceTransaction.setGeneralLedgerId(userBalancePayment.getLedgerId());
        sourceTransaction.setOrderNumber(orderNo);
        sourceTransaction.setTransactionType(TransactionType.BalancePay);
        sourceTransaction.setTransactionStatus(TransactionStatus.Success);
        sourceTransaction.setAmount(total.negate().longValue());
        sourceTransaction.setRemark(remark);
        sourceTransaction.setMeta(Map.of("paymentType",PaymentType.UserWallet, "description", "用户余额支付", "summary", "用户支付"));
        transferModel.setSource(new TransferTransactionsModel.GeneralLedgerTransaction[]{sourceTransaction});
        //构建入账账户
        TransferTransactionsModel.GeneralLedgerTransaction destinationTransaction = new TransferTransactionsModel.GeneralLedgerTransaction();
        destinationTransaction.setGeneralLedgerId(orgWaitSettle.getLedgerId());
        destinationTransaction.setOrderNumber(orderNo);
        destinationTransaction.setTransactionType(TransactionType.BalancePay);
        destinationTransaction.setTransactionStatus(TransactionStatus.Success);
        destinationTransaction.setAmount(total.longValue());
        destinationTransaction.setRemark(remark);
        destinationTransaction.setMeta(Map.of("paymentType",PaymentType.UserWallet, "description", "用户余额支付", "summary", "用户支付"));
        transferModel.setDestinations(new TransferTransactionsModel.GeneralLedgerTransaction[]{destinationTransaction});
        //发起转账
       return transactionLogService.transfer(transferModel);

    }

    public ResultContent<QueryRechargeOrderModel> queryRechargeOrder(QueryRechargeParam param) {
        String projectOid = getCurrentProjectOid();
        String userId = getCurrentUserId();

        if (StringUtils.isEmpty(param.getProjectOid())){
            param.setProjectOid(projectOid);
        }
        if (StringUtils.isEmpty(param.getUserId())){
            param.setUserId(userId);
        }

        Long monthStartTime = DateUtils.getMonthStartTime(param.getYear(), param.getMonth());
        Long monthEndTime = DateUtils.getMonthEndTime(param.getYear(), param.getMonth());
        List<BalanceRechargeOrder> balanceRechargeOrders = rechargeOrderDao.listByMonth(param.getProjectOid(), param.getUserId(), monthStartTime, monthEndTime);
        Long amountTotal = rechargeOrderDao.sumTotal(param.getProjectOid(), param.getUserId(), RechargeOrderStatus.Success, monthStartTime, monthEndTime);
        return ResultContent.buildContent(Map.of("list", balanceRechargeOrders.stream().map(this::toModel).toList(), "amountTotal", amountTotal));
    }

    public ResultContent<Long> queryUserBalance(String projectOid, String userId) {

        if (StringUtils.isEmpty(projectOid)){
            projectOid = getCurrentProjectOid();
        }
        if (StringUtils.isEmpty(userId)){
            userId = getCurrentUserId();
        }

        PayAccount userBalance = payAccountService.getUserChildren(projectOid, userId, PaymentChannelType.BalancePayment);
        ResultContent<GeneralLedgerQueryModel> ret = generalLedgerService.get(userBalance.getLedgerId());
        if (ret.getState().equals(ResultState.Success)) {
            return ResultContent.buildContent(ret.getContent().getBalance());
        }
        return ResultContent.build(ret.getState());
    }

    public ResultContent queryInfo(String orderNo){
        BalanceRechargeOrder rechargeOrder = rechargeOrderDao.findTopByOrderNo(orderNo);
        return ResultContent.buildContent(toModel(rechargeOrder));
    }

    public Object close(String orderNo){
        BalanceRechargeOrder rechargeOrder = rechargeOrderDao.findTopByOrderNo(orderNo);
        if (rechargeOrder==null){
            return com.github.microservice.net.ResultContent.buildFail("订单号不存在");
        }

        if (!rechargeOrder.getStatus().equals(RechargeOrderStatus.Wait)){
            return com.github.microservice.net.ResultContent.buildFail("当前状态不可关闭");
        }

        PayProductParameter<Object> parameter = new PayProductParameter<>();
        String accountName = orgPayAccountService.queryOgPayAccount(rechargeOrder.getProjectOid(), rechargeOrder.getPaymentType());
        parameter.setAccountName(accountName);
        parameter.setMeta(Map.of("orderNo", orderNo));
        ResultContent<Object> closeRet = miniAppPayService.close(parameter);
        if (!closeRet.getState().equals(ResultState.Success)){
            return com.github.microservice.net.ResultContent.buildFail("关闭失败");
        }
        rechargeOrder.setStatus(RechargeOrderStatus.Cancel);
        rechargeOrderDao.save(rechargeOrder);
        return ResultContent.build(ResultState.Success);
    }

    /**
     * 商家退款
     */
    public ResultContent<List<TransactionLogModel>> refund(String projectOid, String oid, String userId, String orderNo, BigDecimal total, String remark){
        //获取用户余额支付子账户
        PayAccount userAccount = payAccountService.getUserChildren(projectOid, userId, PaymentChannelType.BalancePayment);
        //获取机构待结算子账户
        PayAccount orgAccount = payAccountService.getOrgChildren(projectOid, oid, PaymentChannelType.WaitSettle);
        //支付：用户余额子账+ 机构待结算子账-
        //构建转账参数
        TransferTransactionsModel transferModel = new TransferTransactionsModel();
        //构建出账账户
        TransferTransactionsModel.GeneralLedgerTransaction sourceTransaction = new TransferTransactionsModel.GeneralLedgerTransaction();
        sourceTransaction.setAmount(total.negate().longValue());
        sourceTransaction.setTransactionType(TransactionType.Refund);
        sourceTransaction.setTransactionStatus(TransactionStatus.Success);
        sourceTransaction.setOrderNumber(orderNo);
        sourceTransaction.setGeneralLedgerId(orgAccount.getLedgerId());
        sourceTransaction.setRemark(remark);
        sourceTransaction.setMeta(Map.of("paymentType",PaymentType.UserWallet, "description", "用户余额支付", "summary", "用户退款"));
        transferModel.setSource(new TransferTransactionsModel.GeneralLedgerTransaction[]{sourceTransaction});
        //构建入账账户
        TransferTransactionsModel.GeneralLedgerTransaction destinationTransaction = new TransferTransactionsModel.GeneralLedgerTransaction();
        destinationTransaction.setAmount(total.longValue());
        destinationTransaction.setTransactionType(TransactionType.Refund);
        destinationTransaction.setTransactionStatus(TransactionStatus.Success);
        destinationTransaction.setOrderNumber(orderNo);
        destinationTransaction.setGeneralLedgerId(userAccount.getLedgerId());
        destinationTransaction.setRemark(remark);
        destinationTransaction.setMeta(Map.of("paymentType",PaymentType.UserWallet, "description", "用户余额支付", "summary", "用户退款"));
        transferModel.setDestinations(new TransferTransactionsModel.GeneralLedgerTransaction[]{destinationTransaction});
        //调用支付中心转账接口
        return transactionLogService.transfer(transferModel);
    }

    /**
     * 充值退款-从支付渠道退款
     * @return
     */
    public Object channelRefund(String projectId, String userId, String orderNo){
        BalanceRechargeOrder rechargeOrder = rechargeOrderDao.findTopByOrderNo(orderNo);
        if (rechargeOrder==null){
            return com.github.microservice.net.ResultContent.buildFail("订单不存在");
        }

        PayProductParameter<Object> parameter = new PayProductParameter<>();
        String accountName = orgPayAccountService.buildPayAccountName(rechargeOrder.getProjectOid(), rechargeOrder.getPaymentType());
        parameter.setAccountName(accountName);
//        parameter.setMeta(Map.of("orderNo", rechargeOrder.getOrderNo(), ));

        return null;
    }

    @SneakyThrows
    public Object getOpenid(String jscode) {
        MiniAppUserInfoVo miniAppUserInfo = wechatCUtil.getMiniAppUserInfo(jscode);
        if (miniAppUserInfo == null || StringUtil.isNullOrEmpty(miniAppUserInfo.getOpenid())) {
            log.info("无法获取用户信息");
            return com.github.microservice.net.ResultContent.buildFail("无法获取用户信息");
        }
        log.info("用户openid:{}", miniAppUserInfo.getOpenid());
        return com.github.microservice.net.ResultContent.buildContent(miniAppUserInfo);
    }

    private RechargeOrderModel toModel(BalanceRechargeOrder balanceRechargeOrder) {
        RechargeOrderModel rechargeOrderModel = new RechargeOrderModel();
        if (balanceRechargeOrder != null) {
            BeanUtils.copyProperties(balanceRechargeOrder, rechargeOrderModel);
        }
        return rechargeOrderModel;
    }
}
