package cn.iocoder.yudao.module.jx.payment.app;

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.company.entity.Company;
import cn.iocoder.yudao.module.company.service.CompanyService;
import cn.iocoder.yudao.module.company.vo.CompanyRespVO;
import cn.iocoder.yudao.module.course.entity.SchoolCourseOrder;
import cn.iocoder.yudao.module.course.service.SchoolCourseOrderService;
import cn.iocoder.yudao.module.course.vo.SchoolCourseOrderVO;
import cn.iocoder.yudao.module.jx.mapper.DriveSchoolCourseMapper;
import cn.iocoder.yudao.module.jx.payment.mapper.DrivePayMapper;
import cn.iocoder.yudao.module.jx.payment.utils.WechatPayRequests;
import cn.iocoder.yudao.module.jx.service.DrivePayService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.util.WechatPayConfig;
import cn.iocoder.yudao.util.WechatPayUrlEnum;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import java.io.IOException;
import java.security.*;
import java.util.*;

@Slf4j
@RestController
@RequestMapping("/small/jxInfo")
public class SmallProgramJxOrderController {

    @Resource
    private DrivePayService drivePayService;
    @Resource
    private WechatPayConfig wechatPayConfigs;
    @Resource
    private WechatPayRequests wechatPayRequests;
    @Resource
    private DrivePayMapper drivePayMapper;
    @Resource
    private DriveSchoolCourseMapper driveSchoolCourseMapper;

    @Resource
    private AdminUserApi userApi;
    @Resource
    private SchoolCourseOrderService schoolCourseOrderService;

    @Resource
    private CompanyService companyService;


    @PostMapping("/offLinePay")
    @TenantIgnore
    public CommonResult offLinePay(@RequestBody SchoolCourseOrder schoolCourseOrder) {
        SchoolCourseOrderVO schoolCourseOrderVO = BeanUtils.toBean(schoolCourseOrder, SchoolCourseOrderVO.class);
        schoolCourseOrderVO.setPaymentStatus("0");
        boolean exists = false;
        String orderNo;
        int retryCount = 0;
        int maxRetry = 5;

        do {
            // 生成 14 位订单号
            Random random = new Random();
            StringBuilder number = new StringBuilder();

            for (int i = 0; i < 14; i++) {
                int randomDigit = random.nextInt(10);
                number.append(randomDigit);
            }
            orderNo = number.toString();

            // 检查订单号是否已存在
            exists = schoolCourseOrderService.lambdaQuery()
                    .eq(SchoolCourseOrder::getOrderNo, orderNo)
                    .exists();

            retryCount++;
        } while (exists);
        schoolCourseOrderVO.setOrderNo(orderNo);
        schoolCourseOrderService.createSchoolCourseOrder(schoolCourseOrderVO);
        return CommonResult.success("ok");
    }

    @PostMapping("/onLinePay")
    @TenantIgnore
    public Map<String, String> userPayOnLine(@RequestBody SchoolCourseOrder schoolCourseOrder) {
        SchoolCourseOrderVO schoolCourseOrderVO = BeanUtils.toBean(schoolCourseOrder, SchoolCourseOrderVO.class);
        schoolCourseOrderVO.setPaymentStatus("0");

        // 生成 14 位订单号
        Random random = new Random();
        StringBuilder number = new StringBuilder();

        for (int i = 0; i < 14; i++) {
            int randomDigit = random.nextInt(10);
            number.append(randomDigit);
        }
        String randomNumber = number.toString();
        schoolCourseOrderVO.setOrderNo(randomNumber);
        log.info("随机数为 ====================>>> {}", randomNumber);

        Long userId = SecurityFrameworkUtils.getLoginUserId();
        log.info("当前用户id ============>,{}", userId);
        schoolCourseOrderVO.setUserId(Math.toIntExact(userId));


        String orderId = schoolCourseOrderService.createSchoolCourseOrder(schoolCourseOrderVO);
        SchoolCourseOrder dbSchoolCourseOrder = schoolCourseOrderService.getSchoolCourseOrder(orderId);
        String orderNo = dbSchoolCourseOrder.getOrderNo();
        Map<String, String> resMap = new HashMap<>();
        resMap.put("orderNo", orderNo);
        resMap.put("orderId", orderId);

        return resMap;
    }

    @GetMapping("/prepayment")
    @TenantIgnore
    public Map<String, Object> transactions(String type, String orderId, String orderNo, String payType, String tenantId) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException, IOException {
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        AdminUserRespDTO user = userApi.getUser(userId);
        String systemCode = "jiaxiao";

//        SchoolCourseOrder dbSchoolCourseOrder = schoolCourseOrderService.getSchoolCourseOrder(orderId);
//        Company companyInfo = companyService.getCompanyByTenantIdAndSystemCode(tenantId, systemCode);
        SchoolCourseOrder dbSchoolCourseOrder = schoolCourseOrderService.getSchoolCourseOrder(orderId);
        if (dbSchoolCourseOrder == null) {
            throw new IllegalStateException("订单不存在");
        }

        Company companyInfo = companyService.getCompanyByTenantIdAndSystemCode(tenantId, systemCode);
        if (companyInfo == null) {
            throw new IllegalStateException("商户信息不存在");
        }

        // 统一参数封装
        Map<String, Object> params = new HashMap<>(8);
        params.put("appid", companyInfo.getAppId());
        params.put("mchid", companyInfo.getMchId());
        params.put("description", dbSchoolCourseOrder.getCourseName());
        params.put("out_trade_no", orderNo);
        params.put("notify_url", companyInfo.getNotifyUrl());
        Map<String, Object> amountMap = new HashMap<>(4);

        Double amount = 0.0;
        // 金额单位为分
        amount = dbSchoolCourseOrder.getReserveMoney().doubleValue() * 100;
        if (payType.equals("2")) {
            amount = dbSchoolCourseOrder.getReserveMoney().doubleValue() * 100;
        }
        amountMap.put("total", amount.intValue());
        //人民币
        amountMap.put("currency", "CNY");
        params.put("amount", amountMap);

        // 场景信息
        Map<String, Object> sceneInfoMap = new HashMap<>(4);
        // 客户端IP
        sceneInfoMap.put("payer_client_ip", "127.0.0.1");
        // 商户端设备号（门店号或收银设备ID）
        sceneInfoMap.put("device_id", "127.0.0.1");
        // 除H5与JSAPI有特殊参数外，其他的支付方式都一样
        if (type.equals(WechatPayUrlEnum.H5.getType())) {
            Map<String, Object> h5InfoMap = new HashMap<>(4);
            // 场景类型:iOS, Android, Wap
            h5InfoMap.put("type", "IOS");
            sceneInfoMap.put("h5_info", h5InfoMap);
        } else if (type.equals(WechatPayUrlEnum.JSAPI.getType()) || type.equals(WechatPayUrlEnum.SUB_JSAPI.getType())) {
            Map<String, Object> payerMap = new HashMap<>(4);
            payerMap.put("openid", user.getDriverOpenId());
            params.put("payer", payerMap);
        }
        params.put("scene_info", sceneInfoMap);
        String paramsStr = JSON.toJSONString(params);
        log.info("请求参数 ===> {}" + paramsStr);
        String resStr = wechatPayRequests.wechatHttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi", paramsStr);
        Map<String, Object> resMap = JSONObject.parseObject(resStr, new TypeReference<Map<String, Object>>() {
        });
        Map<String, Object> signMap = paySignMsg(resMap.get("prepay_id").toString(), companyInfo.getAppId(), companyInfo.getPrivateKeyStr());
        return signMap;
    }

    String buildMessage(String appId, String timestamp, String nonceStr, String prepay_id) {

        return appId + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + prepay_id + "\n";
    }

    String sign(byte[] message, String privateKeyStr) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException {
        //签名方式
        Signature sign = Signature.getInstance("SHA256withRSA");
        //私钥，通过MyPrivateKey来获取，这是个静态类可以接调用方法 ，需要的是_key.pem文件的绝对路径配上文件名
        PrivateKey privateKey = null;
        if (StringUtils.isNotEmpty(privateKeyStr)) {
            privateKey = PemUtil.loadPrivateKey(privateKeyStr);
        } else {
            privateKey = wechatPayConfigs.getPrivateKey(wechatPayConfigs.getKeyPemPath());
        }

        sign.initSign(privateKey);
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }

    private Map<String, Object> paySignMsg(String prepayId, String appId, String privateKeyStr) throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        long timeMillis = System.currentTimeMillis();
        String timeStamp = timeMillis / 1000 + "";
        String nonceStr = timeMillis + "";
        String packageStr = "prepay_id=" + prepayId;
        // 公共参数
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("nonceStr", nonceStr);
        resMap.put("timeStamp", timeStamp);
        resMap.put("appId", appId);
        resMap.put("package", packageStr);
        // 使用字段appId、timeStamp、nonceStr、package进行签名
        //从下往上依次生成
        String message = buildMessage(appId, timeStamp, nonceStr, packageStr);
        //签名
        String paySign = sign(message.getBytes("utf-8"), privateKeyStr);
        resMap.put("paySign", paySign);
        resMap.put("signType", "RSA");
        return resMap;
    }

    /**
     * 生成新的订单号
     */
    @GetMapping("/generateOrderNo")
    @TenantIgnore
    public String generateOrderNo() {
        // 格式化当前时间，取前11位 yyMMddHHmmss
        String timeStr = new java.text.SimpleDateFormat("yyMMddHHmm")
                .format(new java.util.Date());

        // 补上1位秒数（只取秒的十位）
        String seconds = new java.text.SimpleDateFormat("ss").format(new java.util.Date());
        timeStr += seconds.charAt(0);

        // 生成一位随机数
        int randomDigit = (int) (Math.random() * 10);

        // 拼接前缀+时间+随机数
        return "jx" + timeStr + randomDigit;
    }

}
