package com.gxwebsoft.shop.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.cms.entity.Website;
import com.gxwebsoft.cms.entity.WebsiteField;
import com.gxwebsoft.common.core.config.ConfigProperties;
import com.gxwebsoft.common.core.exception.BusinessException;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.core.utils.RequestUtil;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.shop.entity.*;
import com.gxwebsoft.shop.mapper.OrderMapper;
import com.gxwebsoft.shop.param.OrderParam;
import com.gxwebsoft.shop.service.*;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAConfig;
import com.gxwebsoft.common.system.entity.Payment;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 订单Service实现
 *
 * @author 科技小王子
 * @since 2024-05-14 13:20:04
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
  @Value("${spring.profiles.active}")
  String active;
  @Resource
  private OrderInfoService orderInfoService;
  @Resource
  private OrderGoodsService orderGoodsService;
  @Resource
  private ConfigProperties config;
  @Resource
  private RequestUtil requestUtil;
  @Resource
  private OrderService orderService;
  @Resource
  private UsersService usersService;
  @Resource
  private RedisUtil redisUtil;
//  public static String privateKeyPath = "/Users/gxwebsoft/JAVA/com.gxwebsoft.modules/src/main/resources/cert/apiclient_key.pem";
//  public static String privateCertPath = "/Users/gxwebsoft/JAVA/com.gxwebsoft.core/src/main/resources/cert/apiclient_cert.pem";
//  public static String wechatpayCertPath = "/Users/gxwebsoft/JAVA/com.gxwebsoft.modules/src/main/resources/cert/wechatpay_2DD5A0669263BAE55E52BF3F35BF4A4006A2DAA6.pem";  // 平台证书

  public static String privateKeyPath = "/Users/gxwebsoft/Downloads/ef7f7e0430cb47019d06b93f885bf95f/apiclient_key.pem";
  public static String privateCertPath = "/Users/gxwebsoft/JAVA/com.gxwebsoft.core/src/main/resources/cert/apiclient_cert.pem";
  public static String wechatpayCertPath = "/Users/gxwebsoft/Downloads/ef7f7e0430cb47019d06b93f885bf95f/wechatpay_55729BDEC2502C301BA02CDC28E4CEE4DE4D1DB9.pem";  // 平台证书


  @Override
  public PageResult<Order> pageRel(OrderParam param) {
    PageParam<Order, OrderParam> page = new PageParam<>(param);
    page.setDefaultOrder("sort_number asc, create_time desc");
    List<Order> list = baseMapper.selectPageRel(page, param);

    if (param.getSceneType() != null) {
      final Set<Integer> orderIds = list.stream().map(Order::getOrderId).collect(Collectors.toSet());
      if (!CollectionUtils.isEmpty(orderIds)) {
        // 查询预定订单信息
        if (param.getSceneType().equals("showOrderInfo")) {
          final List<OrderInfo> orderInfoList = orderInfoService.list(new LambdaQueryWrapper<OrderInfo>().in(OrderInfo::getOrderId, orderIds));
          final Map<Integer, List<OrderInfo>> collect = orderInfoList.stream().collect(Collectors.groupingBy(OrderInfo::getOrderId));
          list.forEach(d -> {
            final DateTime date = DateUtil.date(d.getExpirationTime());
            final DateTime now = DateUtil.date();
            d.setTimestamp(date.getTime() - now.getTime());
            if (!collect.isEmpty()) {
              final List<OrderInfo> orderInfos = collect.get(d.getOrderId());
              if (!CollectionUtils.isEmpty(orderInfos)) {
                d.setOrderInfo(orderInfos);
              }
            }
          });
        }
        // 查询商品信息
        if (param.getSceneType().equals("showOrderGoods")) {
          final List<OrderGoods> goodsList = orderGoodsService.list(new LambdaQueryWrapper<OrderGoods>().in(OrderGoods::getOrderId, orderIds));
          final Map<Integer, List<OrderGoods>> collect = goodsList.stream().collect(Collectors.groupingBy(OrderGoods::getOrderId));
          list.forEach(d -> {
            final DateTime date = DateUtil.date(d.getExpirationTime());
            final DateTime now = DateUtil.date();
            d.setTimestamp(date.getTime() - now.getTime());
            if (!collect.isEmpty()) {
              final List<OrderGoods> goods = collect.get(d.getOrderId());
              if (!CollectionUtils.isEmpty(goods)) {
                d.setGoodsList(goods);
              }
            }
          });
        }
      }
    }

    return new PageResult<>(list, page.getTotal());
  }

  @Override
  public List<Order> listRel(OrderParam param) {
    List<Order> list = baseMapper.selectListRel(param);
    // 排序
    PageParam<Order, OrderParam> page = new PageParam<>();
    page.setDefaultOrder("sort_number asc, create_time desc");
    return page.sortRecords(list);
  }

  @Override
  public Order getByIdRel(Integer orderId) {
    OrderParam param = new OrderParam();
    param.setOrderId(orderId);
    Order order = param.getOne(baseMapper.selectListRel(param));
    if (order != null) {
      final List<OrderInfo> list = orderInfoService.list(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderId, orderId));

      // 订单信息
      order.setOrderInfo(list);
      if (!CollectionUtils.isEmpty(list)) {
        final OrderInfo orderInfo = list.get(0);
        final int i = orderInfo.getDateTime().compareTo(DateUtil.today());
      }
      // 订单商品
      final List<OrderGoods> orderGoods = orderGoodsService.list(new LambdaQueryWrapper<OrderGoods>().eq(OrderGoods::getOrderId, orderId));
      order.setGoodsList(orderGoods);
      // 生成订单核销码
//      requestUtil.setTenantId(order.getTenantId().toString());
//      order.setQrcode(requestUtil.getOrderQRCodeUnlimited(order.getOrderNo()));
      return order;
    }
    return null;
  }

  /**
   * 创建微信支付
   *
   * @param order
   * @return
   */
  @Override
  public HashMap<String, String> createWxOrder(Order order) {
    final String uploadPath = config.getUploadPath();   // 服务器本地路径
    final HashMap<String, String> orderInfo = new HashMap<>();
    // 微信小程序(微信支付)
    String key = "mp-weixin:".concat(order.getTenantId().toString());
    final String string = redisUtil.get(key);
//    System.out.println("string = " + string);
    final JSONObject mpWx = JSONObject.parseObject(string);
//    System.out.println("mpWx = " + mpWx);
    String key2 = "Payment:".concat(order.getPayType().toString()).concat(":").concat(order.getTenantId().toString());
    final Payment payment = redisUtil.get(key2, Payment.class);
//    System.out.println("payment = " + payment);

    // 计算金额
    BigDecimal decimal = order.getTotalPrice();
    final BigDecimal multiply = decimal.multiply(new BigDecimal(100));
    // 将 BigDecimal 转换为 Integer
    Integer money = multiply.intValue();
    String privateKey = uploadPath.concat("/file").concat(payment.getApiclientKey());    // 秘钥证书
    String apiclientCert = uploadPath.concat("/file").concat(payment.getApiclientCert());
    // 开发环境配置
    if (active.equals("dev")) {
      privateKey = privateKeyPath;
      apiclientCert = wechatpayCertPath;
    }
    Config config =
      new RSAConfig.Builder()
        .merchantId(payment.getMchId())
        .privateKeyFromPath(privateKey)
        .merchantSerialNumber(payment.getMerchantSerialNumber())
        .wechatPayCertificatesFromPath(apiclientCert)
        .build();

    // 构建service
    JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
    // 跟之前下单示例一样，填充预下单参数
    PrepayRequest request = new PrepayRequest();
    Amount amount = new Amount();
    amount.setTotal(money);
    amount.setCurrency("CNY");
    request.setAmount(amount);
    request.setAppid(mpWx.getString("appId"));
    request.setMchid(payment.getMchId());
    request.setDescription(order.getComments());
    request.setOutTradeNo(order.getOrderNo());
    request.setAttach(order.getTenantId().toString());
    final Payer payer = new Payer();
    payer.setOpenid(order.getOpenid());
    request.setPayer(payer);
    // 测试环境
    if (active.equals("dev")) {
      amount.setTotal(1);
      request.setAmount(amount);
      request.setNotifyUrl("http://jimei-api.natapp1.cc/api/shop/wx-pay/notify/" + order.getTenantId()); // 默认回调地址
    }
    // 生成环境
    if (active.equals("prod")) {
      amount.setTotal(2);
      request.setAmount(amount);
      request.setNotifyUrl("https://server.gxwebsoft.com/api/system/wx-pay/notify/" + order.getTenantId()); // 默认回调地址
    }
//    if (StrUtil.isNotBlank(payment.getNotifyUrl())) {
      // 后台配置的回调地址
//      request.setNotifyUrl(payment.getNotifyUrl().concat("/").concat(order.getTenantId().toString()));
//    }
    System.out.println("request = " + request);
    PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
    orderInfo.put("provider", "wxpay");
    orderInfo.put("timeStamp", response.getTimeStamp());
    orderInfo.put("nonceStr", response.getNonceStr());
    orderInfo.put("package", response.getPackageVal());
    orderInfo.put("signType", "RSA");
    orderInfo.put("paySign", response.getPaySign());
    return orderInfo;
  }


  @Override
  public Order getByOutTradeNo(String outTradeNo) {
    OrderParam param = new OrderParam();
    param.setOrderNo(outTradeNo);
    baseMapper.getByOutTradeNo(param);
    return param.getOne(baseMapper.getByOutTradeNo(param));
  }

  @Override
  public Boolean updateByOutTradeNo(Order order) {
    baseMapper.updateByOutTradeNo(order);
    return true;
  }

  @Override
  @Transactional(rollbackFor = {Exception.class})
  public Boolean payByBalance(Order order) {
    final User loginUser = order.getLoginUser();

    if (loginUser.getBalance().compareTo(order.getTotalPrice()) < 0) {
      throw new BusinessException("余额不足");
    }

    // 发起网络请求(更新余额接口)
    final RequestUtil requestUtil = new RequestUtil();
    requestUtil.setAccessToken(order.getAccessToken());
    requestUtil.setTenantId(order.getTenantId().toString());
    String api = "/system/user/updateUserBalance";  // 更新余额接口
    final BigDecimal subtract = loginUser.getBalance().subtract(order.getTotalPrice());

    loginUser.setBalance(subtract);
    // 累加会员积分
    String key = "SiteInfo:" + order.getTenantId();
    final String siteInfo = redisUtil.get(key);
    // 从缓存读取信息
    if (StrUtil.isNotBlank(siteInfo)) {
      final Website website = JSONObject.parseObject(siteInfo, Website.class);
      final List<WebsiteField> fields = website.getFields();
      if (!CollectionUtils.isEmpty(fields)) {
        fields.forEach(d -> {
          if (d.getName().equals("integral_enabled") && d.getValue().equals("1")) {
            loginUser.setPoints(loginUser.getPoints() + order.getPayPrice().intValue());
          }
        });
      }
    }
    final ApiResult<?> apiResult = requestUtil.updateUserBalance(api, loginUser);
    if (apiResult.getCode().equals(0)) {
      // 修改订单状态
      order.setPayStatus(1);
      order.setPayTime(DateUtil.date());
      order.setExpirationTime(DateUtil.offset(DateUtil.date(), DateField.YEAR, 10));
      orderService.updateById(order);
      orderInfoService.update(new LambdaUpdateWrapper<OrderInfo>().eq(OrderInfo::getOrderId, order.getOrderId()).set(OrderInfo::getPayStatus, 1));
      // 发放积分
      usersService.addIntegral(order);
      return true;
    }
    return true;
  }
}
