package com.gxwebsoft.love.controller;

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.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.core.config.ConfigProperties;
import com.gxwebsoft.common.core.utils.CommonUtil;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.Setting;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.common.system.mapper.SettingMapper;
import com.gxwebsoft.common.system.param.SettingParam;
import com.gxwebsoft.common.system.service.SettingService;
import com.gxwebsoft.common.system.service.UserRoleService;
import com.gxwebsoft.common.system.service.UserService;
import com.gxwebsoft.love.entity.UserPlanLog;
import com.gxwebsoft.love.entity.UserPlanPrice;
import com.gxwebsoft.love.param.UserPlanLogParam;
import com.gxwebsoft.love.service.UserPlanLogService;
import com.gxwebsoft.love.service.UserPlanPriceService;
import com.gxwebsoft.shop.entity.UserReferee;
import com.gxwebsoft.shop.service.UserGradeService;
import com.gxwebsoft.shop.service.UserRefereeService;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RSANotificationConfig;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
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 io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.gxwebsoft.common.core.constants.OrderConstants.PAY_STATUS_NO_PAY;
import static com.gxwebsoft.common.core.constants.OrderConstants.PAY_STATUS_SUCCESS;

/**
 * 会员特权购买记录表控制器
 *
 * @author 科技小王子
 * @since 2023-06-20 18:07:50
 */
@Api(tags = "会员特权购买记录表管理")
@RestController
@RequestMapping("/api/love/user-plan-log")
public class UserPlanLogController extends BaseController {
  @Resource
  private UserPlanLogService userPlanLogService;
  @Resource
  private UserPlanPriceService userPlanPriceService;
  @Resource
  private SettingService settingService;
  @Resource
  private ConfigProperties config;
  @Resource
  private SettingMapper settingMapper;
  @Resource
  private UserRefereeService userRefereeService;
  @Resource
  private UserService userService;

  @PreAuthorize("hasAuthority('love:userPlanLog:list')")
  @OperationLog
  @ApiOperation("分页查询会员特权购买记录表")
  @GetMapping("/page")
  public ApiResult<PageResult<UserPlanLog>> page(UserPlanLogParam param) {
    // 使用关联查询
    return success(userPlanLogService.pageRel(param));
  }

  @PreAuthorize("hasAuthority('love:userPlanLog:list')")
  @OperationLog
  @ApiOperation("查询全部会员特权购买记录表")
  @GetMapping()
  public ApiResult<List<UserPlanLog>> list(UserPlanLogParam param) {
    // 使用关联查询
    return success(userPlanLogService.listRel(param));
  }

  @PreAuthorize("hasAuthority('love:userPlanLog:list')")
  @OperationLog
  @ApiOperation("根据id查询会员特权购买记录表")
  @GetMapping("/{id}")
  public ApiResult<UserPlanLog> get(@PathVariable("id") Integer id) {
    return success(userPlanLogService.getByIdRel(id));
  }

  @PreAuthorize("hasAuthority('love:userPlanLog:save')")
  @OperationLog
  @ApiOperation("添加会员特权购买记录表")
  @PostMapping()
  public ApiResult<?> save(@RequestBody UserPlanLog userPlanLog) {
    // 记录当前登录用户id
    User loginUser = getLoginUser();
    if (loginUser != null) {
      userPlanLog.setUserId(loginUser.getUserId());
      userPlanLog.setOpenid(loginUser.getOpenid());
      // 更新绑定关系
      if (userPlanLog.getDealerId() != null && userPlanLog.getDealerId() > 0) {
        userRefereeService.remove(new LambdaQueryWrapper<UserReferee>().eq(UserReferee::getUserId, loginUser.getUserId()));
        final UserReferee userReferee = new UserReferee();
        userReferee.setUserId(userPlanLog.getUserId());
        userReferee.setDealerId(userPlanLog.getDealerId());
        if (userService.getById(userPlanLog.getDealerId()) == null) {
          return fail("邀请人ID不存在");
        }
        userRefereeService.save(userReferee);
      }
    }
    final UserPlanPrice price = userPlanPriceService.getByIdRel(userPlanLog.getPriceId());
    userPlanLog.setLogNo(CommonUtil.createOrderNo());
    userPlanLog.setMoney(price.getPrice());
    userPlanLog.setPriceName(price.getName());
    userPlanLog.setPlanId(price.getPlanId());
    userPlanLog.setComments(price.getPlanName());
    userPlanLog.setType(price.getType());
    userPlanLog.setGradeId(price.getGradeId());
    userPlanLog.setAddress(userPlanLog.getAddress());

    if (userPlanLog.getTotalPrice() != null) {
      // 订单金额为0
      if (userPlanLog.getTotalPrice().equals(new BigDecimal("0.00"))) {
        userPlanLog.setMoney(userPlanLog.getTotalPrice());
        userPlanLog.setPayStatus(PAY_STATUS_SUCCESS);
        userPlanLog.setStatus(1);
        userPlanLog.setIsSettled(0);
        userPlanLogService.save(userPlanLog);
        return success("支付成功", null);
      }
      // 自定义金额
      userPlanLog.setMoney(userPlanLog.getTotalPrice());
    }


    // 保存购买记录
    if (userPlanLogService.save(userPlanLog)) {
      return success("订单创建成功", this.createOrder(userPlanLog));
    }
    return fail("订单创建失败");
  }

  @PreAuthorize("hasAuthority('love:userPlanLog:list')")
  @ApiOperation("待支付订单支付")
  @GetMapping("/onPay/{id}")
  public ApiResult<?> onPay(@PathVariable("id") Integer id) {
    final UserPlanLog userPlanLog = userPlanLogService.getByIdRel(id);
    User loginUser = getLoginUser();
    if (loginUser != null) {
      userPlanLog.setUserId(loginUser.getUserId());
      userPlanLog.setOpenid(loginUser.getOpenid());
      userPlanLog.setLogNo(CommonUtil.createOrderNo());
    }
    System.out.println("userPlanLog = " + userPlanLog);
    return success("订单创建成功", this.createOrder(userPlanLog));
  }

  /**
   * 创建订单
   */
  private HashMap<String, String> createOrder(UserPlanLog userPlanLog) {

    final String uploadPath = config.getUploadPath();   // 服务器本地路径
    final JSONObject mpWx = settingService.getBySettingKey("mp-weixin");
    final JSONObject payment = settingService.getBySettingKey("payment");

    // 计算金额
    BigDecimal decimal = userPlanLog.getMoney();
    final BigDecimal multiply = decimal.multiply(new BigDecimal(100));
    // 将 BigDecimal 转换为 Integer
    Integer money = multiply.intValue();

    final String appId = mpWx.getString("appId");
    final String mchId = payment.getString("mchId");
    final String openid = userPlanLog.getOpenid();  // openid
    final String notifyUrl = config.getServerUrl() + "/love/user-plan-log/wx-pay/notify/" + userPlanLog.getTenantId(); // 异步通知地址
    final String privateKey = uploadPath.concat("file").concat(payment.getString("apiclientKey"));    // 秘钥证书
    final String apiclientCert = uploadPath.concat("file").concat(payment.getString("apiclientCert"));
    final String merchantSerialNumber = payment.getString("merchantSerialNumber");     // 证书序列号
    final String apiV3key = payment.getString("wechatApiKey");

//    System.out.println("privateKey = " + privateKey);
//    System.out.println("apiclientCert = " + apiclientCert);
//    System.out.println("merchantSerialNumber = " + merchantSerialNumber);
//    System.out.println("apiV3key = " + apiV3key);
//    System.out.println("mchId = " + mchId);
//    System.out.println("appId = " + appId);

    Config config =
      new RSAConfig.Builder()
        .merchantId(mchId)
        .privateKeyFromPath(privateKey)
        .merchantSerialNumber(merchantSerialNumber)
        .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(appId);
    request.setMchid(mchId);
    request.setDescription(userPlanLog.getComments());
    request.setNotifyUrl(notifyUrl);
    request.setOutTradeNo(userPlanLog.getLogNo());
    request.setAttach(userPlanLog.getTenantId().toString());
    final Payer payer = new Payer();
    payer.setOpenid(openid);
    request.setPayer(payer);

    PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
//    System.out.println("response = " + response);

    final HashMap<String, String> orderInfo = new HashMap<>();
    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;
  }

  @ApiModelProperty("异步通知")
  @OperationLog
  @PostMapping("/wx-pay/notify/{tenantId}")
  public String wxNotify(@RequestHeader Map<String, String> header, @RequestBody String body, @PathVariable("tenantId") Integer tenantId) {
    System.out.println("异步通知*************** = ");
//    System.out.println("request header = " + header);
//    System.out.println("request body = " + body);
//    System.out.println("tenantId = " + tenantId);

    // 获取支付配置信息用于解密
    final SettingParam param = new SettingParam();
    param.setSettingKey("payment");
    param.setTenantId(tenantId);
    final String uploadPath = config.getUploadPath();   // 服务器本地路径
    final Setting payment = settingMapper.getBySettingKeyIgnore(param);
    final JSONObject jsonObject = JSONObject.parseObject(payment.getContent());
    final String apiV3key = jsonObject.getString("wechatApiKey");
    final String apiclientCert = uploadPath.concat("file").concat(jsonObject.getString("apiclientCert"));

//    System.out.println("apiV3key ====== " + apiV3key);
//    System.out.println("payment ===== " + payment);

    com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder()
      .serialNumber(header.get("wechatpay-serial"))
      .nonce(header.get("wechatpay-nonce"))
      .signature(header.get("wechatpay-signature"))
      .timestamp(header.get("wechatpay-timestamp"))
      .body(body)
      .build();

    // 如果已经初始化了 RSAAutoCertificateConfig，可直接使用
    // 没有的话，则构造一个
    NotificationConfig config = new RSANotificationConfig.Builder()
      .apiV3Key(apiV3key)
      .certificatesFromPath(apiclientCert)
      .build();

    // 初始化 NotificationParser
    NotificationParser parser = new NotificationParser(config);

    // 以支付通知回调为例，验签、解密并转换成 Transaction
    try {
      Transaction transaction = parser.parse(requestParam, Transaction.class);
      final String outTradeNo = transaction.getOutTradeNo();
      final Integer total = transaction.getAmount().getTotal();
      final String tradeStateDesc = transaction.getTradeStateDesc();
//      final Transaction.TradeStateEnum tradeState = transaction.getTradeState();
//      final Transaction.TradeTypeEnum tradeType = transaction.getTradeType();
//      System.out.println("transaction = " + transaction);
//      System.out.println("tradeStateDesc = " + tradeStateDesc);
//      System.out.println("tradeType = " + tradeType);
//      System.out.println("tradeState = " + tradeState);
//      System.out.println("outTradeNo = " + outTradeNo);
//      System.out.println("amount = " + total);

      if (StrUtil.equals("支付成功", tradeStateDesc)) {
        // 1. 查询要处理的订单
        final UserPlanLog log = userPlanLogService.getByOutTradeNo(outTradeNo);
        System.out.println("log = " + log);
        // 2. 已支付则跳过
        if (log.getPayStatus().equals(PAY_STATUS_SUCCESS)) {
          return "SUCCESS";
        }
        // 2. 未支付则处理更新订单状态
        if (log.getPayStatus().equals(PAY_STATUS_NO_PAY)) {
          // 3. TODO 处理会员等级

          // 4. TODO 处理过期时间

          log.setPayStatus(PAY_STATUS_SUCCESS);
          log.setPayTime(DateUtil.date());
          // 实际付款金额：Integer除以100后转BigDecimal
          DecimalFormat df = new DecimalFormat("0.00");
          final String format = df.format(total / 100);
          log.setPayPrice(new BigDecimal(format));
          userPlanLogService.updateByOutTradeNo(log);
          return "SUCCESS";
        }
      }
    } catch (Exception $e) {
      System.out.println($e.getMessage());
    }

    return "fail";
  }

  @PreAuthorize("hasAuthority('love:userPlanLog:update')")
  @OperationLog
  @ApiOperation("修改会员特权购买记录表")
  @PutMapping()
  public ApiResult<?> update(@RequestBody UserPlanLog userPlanLog) {
    if (userPlanLogService.updateById(userPlanLog)) {
      return success("修改成功");
    }
    return fail("修改失败");
  }

  @PreAuthorize("hasAuthority('love:userPlanLog:remove')")
  @OperationLog
  @ApiOperation("删除会员特权购买记录表")
  @DeleteMapping("/{id}")
  public ApiResult<?> remove(@PathVariable("id") Integer id) {
    if (userPlanLogService.removeById(id)) {
      return success("删除成功");
    }
    return fail("删除失败");
  }

  @PreAuthorize("hasAuthority('love:userPlanLog:save')")
  @OperationLog
  @ApiOperation("批量添加会员特权购买记录表")
  @PostMapping("/batch")
  public ApiResult<?> saveBatch(@RequestBody List<UserPlanLog> list) {
    if (userPlanLogService.saveBatch(list)) {
      return success("添加成功");
    }
    return fail("添加失败");
  }

  @PreAuthorize("hasAuthority('love:userPlanLog:update')")
  @OperationLog
  @ApiOperation("批量修改会员特权购买记录表")
  @PutMapping("/batch")
  public ApiResult<?> removeBatch(@RequestBody BatchParam<UserPlanLog> batchParam) {
    if (batchParam.update(userPlanLogService, "log_id")) {
      return success("修改成功");
    }
    return fail("修改失败");
  }

  @PreAuthorize("hasAuthority('love:userPlanLog:remove')")
  @OperationLog
  @ApiOperation("批量删除会员特权购买记录表")
  @DeleteMapping("/batch")
  public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
    if (userPlanLogService.removeByIds(ids)) {
      return success("删除成功");
    }
    return fail("删除失败");
  }

  @OperationLog
  @ApiOperation("创建会员订单")
  @GetMapping("/getPlanByPriceId/{priceId}")
  public ApiResult<?> getPlanByPriceId(@PathVariable("priceId") Integer priceId) {
    final UserPlanPrice price = userPlanPriceService.getByIdRel(priceId);
    return success(price);
  }

//  @ApiModelProperty("异步通知")
//  @OperationLog
//  @PostMapping("/wx-pay/test/{id}")
//  public ApiResult<?> test(@RequestHeader Map<String, String> header, @PathVariable("id") Integer id) {
////    final UserPlanLog log = userPlanLogService.getByOutTradeNo("2023062223063683");
////    System.out.println("byOutTradeNo = " + log);
////    final UserRole userRole = new UserRole();
////    userRole.setUserId(log.getUserId());
////    userRole.setRoleId(log.getRoleId());
////    userRole.setTenantId(log.getTenantId());
////    userRoleService.save(userRole);
////    return success(userRole);
//    return success("");
//  }
}
