package com.ruoyi.app.pay;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.app.order.dto.OrderPushBodyDto;
import com.ruoyi.app.utils.PayPush;
import com.ruoyi.app.utils.event.PushEventService;
import com.ruoyi.app.utils.newebpay.NewebPay;
import com.ruoyi.app.utils.newebpay.NewebPayConfig;
import com.ruoyi.app.utils.newebpay.NewebPayEncryptUtil;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.system.domain.InfoUser;
import com.ruoyi.system.domain.IpnLog;
import com.ruoyi.system.domain.PosOrder;
import com.ruoyi.system.domain.PosOrderPayment;
import com.ruoyi.system.domain.PosStoreNewebpay;
import com.ruoyi.system.mapper.RiderPositionMapper;
import com.ruoyi.system.service.IInfoUserService;
import com.ruoyi.system.service.IIpnLogService;
import com.ruoyi.system.service.IPosOrderPaymentService;
import com.ruoyi.system.service.IPosOrderService;
import com.ruoyi.system.service.IPosStoreNewebpayService;
import com.ruoyi.system.utils.Auth;
import com.ruoyi.system.utils.JwtUtil;
import com.ruoyi.system.utils.OrderLogHelper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 蓝新金流(NewebPay) 线上支付 Controller。
 *
 * <p><strong>已废弃（2026-09-02 确认）</strong>：蓝新支付方案已放弃，本 Controller 从未在生产启用，
 * 也没有任何业务代码引用。不要参考其业务逻辑，不要在其上做增量修改；如需在线支付能力，
 * 以 {@code specs/023-payment-provider-routing} 的通用支付编排设计为准。
 *
 * <p>本期实现：
 * <ul>
 *   <li>{@code POST /pay/newebpay/create} — 发起 MPG 幕前支付（US1）。</li>
 *   <li>{@code POST /pay/newebpay/notify} — NotifyURL 支付结果回调（US2，@Anonymous）。</li>
 *   <li>{@code GET|POST /pay/newebpay/return} — ReturnURL 完成页引导（US2，@Anonymous）。</li>
 * </ul>
 * 单笔查询 /pay/newebpay/query（US5）后续补充。
 *
 * <p>回调成功后的业务链路（更新 payStatus + 订单日志 + 推送用户/商家/骑手）参照
 *
 * @author ruoyi
 * @date 2026-06-22
 */
@RestController
@RequestMapping("/pay/newebpay")
@Deprecated
public class NewebpayPayController extends BaseController {

    private static final Logger log = LoggerFactory.getLogger(NewebpayPayController.class);

    /** payType 取值：蓝新在线支付。蓝新方案已废弃，该值不会再被生产代码写入。 */
    @Deprecated
    public static final String PAY_TYPE_NEWEBPAY = "6";

    @Autowired
    private IPosOrderService posOrderService;
    @Autowired
    private IPosStoreNewebpayService posStoreNewebpayService;
    @Autowired
    private IPosOrderPaymentService posOrderPaymentService;
    @Autowired
    private NewebPay newebPay;
    @Autowired
    private IInfoUserService infoUserService;
    @Autowired
    private RiderPositionMapper riderPositionMapper;
    @Autowired
    private PushEventService pushEventService;
    @Autowired
    private OrderLogHelper orderLogHelper;
    @Autowired
    private IIpnLogService ipnLogService;
    /** 复用 PayController 的可接单骑手异步推送（避免重写复杂调度）。 */


    @Value("${newebpay.base-url}")
    private String baseUrl;
    @Value("${newebpay.notify-url}")
    private String notifyUrl;
    @Value("${newebpay.return-url}")
    private String returnUrl;
    @Value("${newebpay.front-result-url}")
    private String frontResultUrl;
    @Value("${newebpay.mpg-version}")
    private String mpgVersion;

    // ============================ US1：发起 MPG 幕前支付 ============================

    /**
     * 发起蓝新 MPG 幕前支付。校验订单 → 查门店启用凭证 → 生成商店订单号 →
     * 组装并加密 TradeInfo → 落流水 + 更新订单 payType → 返回 form 字段供前端 Form Post 跳转蓝新付款页。
     */
    @Anonymous
    @Auth
    @RepeatSubmit(interval = 1000, message = "请求过于频繁")
    @PostMapping("/create")
    public AjaxResult create(@RequestParam String orderid, HttpServletRequest request) {
        String token = request.getHeader("token");
        JwtUtil jwtUtil = new JwtUtil();
        String userId;
        try {
            userId = jwtUtil.getusid(token);
        } catch (Exception e) {
            return error(MessageUtils.message("no.order.id.error"));
        }
        if (userId == null || userId.isEmpty()) {
            return error("请先登录");
        }

        PosOrder order = posOrderService.getOne(new QueryWrapper<PosOrder>().eq("dd_id", orderid));
        if (order == null) {
            return error(MessageUtils.message("no.order.id.error"));
        }
        if (order.getUserId() == null || !userId.equals(String.valueOf(order.getUserId()))) {
            return error("无权操作该订单");
        }
        if (order.getPayStatus() != null && order.getPayStatus() == 1L) {
            return error("订单已支付");
        }
        if (order.getAmount() == null || order.getAmount() <= 0) {
            return error("订单金额异常");
        }

        Long storeId = order.getMdId();
        PosStoreNewebpay cfg = posStoreNewebpayService.getEnabledConfig(storeId);
        if (cfg == null) {
            return error("该门店暂不支持线上支付");
        }

        String merchantOrderNo = genMerchantOrderNo(orderid);

        // TradeInfo 明文（NDNF §4.2.1）
        Map<String, Object> tradeParams = new LinkedHashMap<>();
        tradeParams.put("MerchantID", cfg.getMerchantId());
        tradeParams.put("RespondType", "JSON");
        tradeParams.put("TimeStamp", String.valueOf(System.currentTimeMillis() / 1000L));
        tradeParams.put("Version", mpgVersion);
        tradeParams.put("MerchantOrderNo", merchantOrderNo);
        tradeParams.put("Amt", order.getAmount());
        tradeParams.put("ItemDesc", "order " + orderid);
        tradeParams.put("NotifyURL", notifyUrl);
        tradeParams.put("ReturnURL", returnUrl);
        applyPaymentSwitch(tradeParams, cfg.getEnabledPayments());

        NewebPayConfig npc = new NewebPayConfig(cfg.getMerchantId(), cfg.getHashKey(), cfg.getHashIv());
        Map<String, String> form = newebPay.createMpgForm(baseUrl, npc, tradeParams, mpgVersion);

        posOrderPaymentService.createPayment(orderid, merchantOrderNo, storeId, cfg.getMerchantId(), order.getAmount());

        PosOrder upd = new PosOrder();
        upd.setId(order.getId());
        upd.setPayType(PAY_TYPE_NEWEBPAY);
        upd.setPayUrl(form.get("gatewayUrl"));
        posOrderService.saveOrUpdate(upd);

        return success(MessageUtils.message("no.order.create.success"), form);
    }

    // ============================ US2：NotifyURL 支付结果回调 ============================

    /**
     * 蓝新支付结果背景通知（@Anonymous，蓝新服务器 Form Post）。
     *
     * <p>记 IPN 日志 → 按 MerchantID 查凭证 → 验签 TradeSha → 解密 TradeInfo →
     * 幂等(trade_no) + 金额校验 + 订单关联 → 成功则更新 payStatus=1 并推送用户/商家/骑手；
     * 失败则记录。任何异常都不抛错响应（蓝新收到非成功会重试），但绝不错误更新订单。
     */
    @Anonymous
    @PostMapping("/notify")
    public JSONObject notify(HttpServletRequest request) {
        JSONObject resp = new JSONObject();
        resp.put("Status", "SUCCESS");
        resp.put("Message", "OK");

        Map<String, Object> form = collectForm(request);
        String ip = new com.ruoyi.app.utils.IpUtils().getIpAddr(request);
        String merchantId = (String) form.get("MerchantID");
        String tradeInfo = (String) form.get("TradeInfo");
        String tradeSha = (String) form.get("TradeSha");
        String status = (String) form.get("Status");

        // 记录 IPN 日志
        try {
            IpnLog ipnLog = new IpnLog();
            ipnLog.setIp(ip);
            ipnLog.setIpnLog(form.toString());
            ipnLogService.insertIpnLog(ipnLog);
        } catch (Exception e) {
            log.warn("记蓝新 IPN 日志失败", e);
        }

        PosStoreNewebpay cfg = posStoreNewebpayService.getByMerchantId(merchantId);
        if (cfg == null || cfg.getHashKey() == null || tradeInfo == null) {
            log.warn("蓝新回调无匹配凭证或缺少 TradeInfo: merchantId={}", merchantId);
            return resp;
        }

        // 验签
        String expectedSha = NewebPayEncryptUtil.genTradeSha(tradeInfo, cfg.getHashKey(), cfg.getHashIv());
        if (tradeSha == null || !tradeSha.equals(expectedSha)) {
            log.warn("蓝新回调验签失败: merchantId={}, expected={}, got={}", merchantId, expectedSha, tradeSha);
            return resp;
        }

        // 解密
        Map<String, Object> d;
        try {
            d = parseQuery(NewebPayEncryptUtil.decrypt(tradeInfo, cfg.getHashKey(), cfg.getHashIv()));
        } catch (Exception e) {
            log.warn("蓝新回调解密失败: merchantId={}", merchantId, e);
            return resp;
        }

        String tradeNo = getStr(d, "TradeNo");
        String merchantOrderNo = getStr(d, "MerchantOrderNo");

        // 幂等：同 tradeNo 已成功则直接返回
        PosOrderPayment exist = posOrderPaymentService.getByTradeNo(tradeNo);
        if (exist != null && exist.getPayStatus() != null && exist.getPayStatus() == 1) {
            return resp;
        }

        // 订单关联
        PosOrderPayment payment = posOrderPaymentService.getByMerchantOrderNo(merchantOrderNo);
        if (payment == null) {
            log.warn("蓝新回调无对应发起记录: merchantOrderNo={}", merchantOrderNo);
            return resp;
        }
        String ddId = payment.getDdId();
        PosOrder order = posOrderService.getOne(new QueryWrapper<PosOrder>().eq("dd_id", ddId));
        if (order == null) {
            log.warn("蓝新回调订单不存在: ddId={}", ddId);
            return resp;
        }

        // 金额校验
        int amt = parseInt(getStr(d, "Amt"), -1);
        if (amt < 0 || order.getAmount() == null || order.getAmount() != amt) {
            log.error("蓝新回调金额不符: ddId={}, orderAmt={}, callbackAmt={}", ddId, order.getAmount(), amt);
            return resp;
        }

        String payType = mapPaymentType(d);
        String auth = getStr(d, "Auth");
        Date payTime = parsePayTime(getStr(d, "PayTime"));

        if ("SUCCESS".equals(status)) {
            int n = posOrderPaymentService.markSuccess(ddId, merchantOrderNo, payment.getStoreId(),
                    merchantId, amt, tradeNo, payType, auth, payTime, d.toString());
            if (n > 0) {
                // 首次成功：更新订单支付状态并推送（state 保持 0 待商家接单）
                handlePaymentSuccess(order, d);
            }
        } else {
            posOrderPaymentService.markFail(merchantOrderNo, tradeNo, payType, d.toString());
            log.warn("蓝新回调交易失败: ddId={}, status={}, message={}", ddId, status, getStr(d, "Message"));
        }
        return resp;
    }

    /**
     * 支付完成返回页（@Anonymous）。仅引导回前端结果页，<b>不</b>修改订单状态（状态以 notify 为准）。
     */
    @Anonymous
    @RequestMapping(value = "/return", method = {org.springframework.web.bind.annotation.RequestMethod.GET,
            org.springframework.web.bind.annotation.RequestMethod.POST})
    public void returnCallback(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String ddId = "";
        try {
            Map<String, Object> form = collectForm(request);
            String merchantId = (String) form.get("MerchantID");
            String tradeInfo = (String) form.get("TradeInfo");
            PosStoreNewebpay cfg = posStoreNewebpayService.getByMerchantId(merchantId);
            if (cfg != null && cfg.getHashKey() != null && tradeInfo != null) {
                Map<String, Object> d = parseQuery(NewebPayEncryptUtil.decrypt(tradeInfo, cfg.getHashKey(), cfg.getHashIv()));
                PosOrderPayment p = posOrderPaymentService.getByMerchantOrderNo(getStr(d, "MerchantOrderNo"));
                if (p != null) {
                    ddId = p.getDdId();
                }
            }
        } catch (Exception e) {
            log.warn("蓝新 ReturnURL 解析失败", e);
        }
        String sep = frontResultUrl.contains("?") ? "&" : "?";
        response.sendRedirect(frontResultUrl + sep + "ddId=" + URLEncoder.encode(ddId, StandardCharsets.UTF_8));
    }

    // ============================ 支付成功业务链路（参照 PayController.payipn） ============================

    /** 支付成功：更新订单 payStatus=1（state 不变）+ 订单日志 + 推送用户/商家/骑手。 */
    private void handlePaymentSuccess(PosOrder order, Map<String, Object> decryptedMap) {
        try {
            PosOrder upd = new PosOrder();
            upd.setId(order.getId());
            upd.setState(0L);
            upd.setPayStatus(1L);
            posOrderService.saveOrUpdate(upd);

            orderLogHelper.logSync(String.valueOf(order.getDdId()), 0, null, "系统", "系统收到蓝新支付成功回调");

            InfoUser user = order.getUserId() == null ? null : infoUserService.getById(order.getUserId());
            InfoUser shanghu = order.getShId() == null ? null : infoUserService.getById(order.getShId());
            if (user == null) {
                return;
            }
            PayPush push = new PayPush();
            Map<String, Object> orderMap = OrderPushBodyDto.getMap(String.valueOf(order.getDdId()), "1", 0, 1);
            String json = OrderPushBodyDto.margeMapGetJsonString(orderMap, decryptedMap);

            String title = MessageUtils.message("no.message.push.message");
            push.apppush(user.getCid(), title, MessageUtils.message("no.message.push.payment.success"), json);
            pushEventService.PublisherEvent(user.getUserId(), title, MessageUtils.message("no.message.push.payment.success"), json);

            if (shanghu != null) {
                push.shpush(shanghu.getCid(), title, MessageUtils.message("no.message.push.new.order"), json);
                pushEventService.PublisherEvent(shanghu.getUserId(), title, MessageUtils.message("no.message.push.new.order"), json);
            }

            // 可接单骑手推送（外卖），复用 PayController 的异步实现
            try {
                String body = OrderPushBodyDto.getJson(String.valueOf(order.getDdId()), String.valueOf(order.getState()), 1);
              //推送可接单骑手
            } catch (Exception e) {
                log.warn("蓝新支付成功骑手推送异常: ddId={}", order.getDdId(), e);
            }
        } catch (Exception e) {
            log.error("蓝新支付成功业务处理异常: ddId={}", order.getDdId(), e);
        }
    }

    // ============================ 辅助 ============================

    private static String genMerchantOrderNo(String orderid) {
        String safe = orderid == null ? "" : orderid.replaceAll("[^A-Za-z0-9_]", "");
        return "NB" + safe;
    }

    private static void applyPaymentSwitch(Map<String, Object> params, String enabledPayments) {
        if (enabledPayments == null || enabledPayments.isEmpty()) {
            params.put("CREDIT", 1);
            return;
        }
        String eps = enabledPayments.toUpperCase();
        params.put("CREDIT", eps.contains("CREDIT") ? 1 : 0);
        params.put("LINEPAY", eps.contains("LINEPAY") ? 1 : 0);
        params.put("APPLEPAY", eps.contains("APPLEPAY") ? 1 : 0);
    }

    /** 收集 form 参数到 Map（值非空的单值参数）。 */
    private static Map<String, Object> collectForm(HttpServletRequest request) {
        Map<String, Object> m = new LinkedHashMap<>();
        Enumeration<String> names = request.getParameterNames();
        while (names.hasMoreElements()) {
            String n = names.nextElement();
            String[] vals = request.getParameterValues(n);
            if (vals != null && vals.length == 1 && !vals[0].isEmpty()) {
                m.put(n, vals[0]);
            }
        }
        return m;
    }

    /** 解析 a=1&b=2（URL decode）为 Map。 */
    private static Map<String, Object> parseQuery(String query) {
        Map<String, Object> m = new LinkedHashMap<>();
        if (query == null || query.isEmpty()) {
            return m;
        }
        for (String pair : query.split("&")) {
            int idx = pair.indexOf('=');
            if (idx <= 0) {
                continue;
            }
            String k = urlDecode(pair.substring(0, idx));
            String v = idx + 1 <= pair.length() ? urlDecode(pair.substring(idx + 1)) : "";
            m.put(k, v);
        }
        return m;
    }

    private static String urlDecode(String s) {
        try {
            return URLDecoder.decode(s, StandardCharsets.UTF_8);
        } catch (Exception e) {
            return s;
        }
    }

    private static String getStr(Map<String, Object> m, String k) {
        Object v = m.get(k);
        return v == null ? "" : v.toString();
    }

    private static int parseInt(String s, int def) {
        try {
            return Integer.parseInt(s);
        } catch (Exception e) {
            return def;
        }
    }

    private static Date parsePayTime(String s) {
        if (s == null || s.isEmpty()) {
            return null;
        }
        try {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(s);
        } catch (Exception e) {
            return null;
        }
    }

    /** 蓝新回调支付方式映射：优先 PaymentMethod（APPLEPAY），否则 PaymentType（CREDIT/LINEPAY...）。 */
    private static String mapPaymentType(Map<String, Object> d) {
        String pm = getStr(d, "PaymentMethod");
        if (!pm.isEmpty()) {
            return pm.toUpperCase();
        }
        return getStr(d, "PaymentType").toUpperCase();
    }

    // TODO US5: POST /pay/newebpay/query（单笔查询 + 补单）
}
