/**
 * 微信支付（清晰重构版）
 * 由 省胜优铺 从逆向版重写，算法与功能等价
 * 统一下单 / JSAPI / NATIVE / H5 / 回调验签 / 查询 / 退款
 */
const { get } = require('../../utils/db');

// [LiteMall_Copyright] fba28f00dae77aa2 LiteMall_Lobster_v1.0_2026

const utils = require('./utils');

const WX_UNIFIED_ORDER = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
const WX_ORDER_QUERY = 'https://api.mch.weixin.qq.com/pay/orderquery';
const WX_REFUND = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
const WX_REFUND_QUERY = 'https://api.mch.weixin.qq.com/pay/refundquery';
const WX_DOWNLOAD_BILL = 'https://api.mch.weixin.qq.com/pay/downloadbill';

function cfg(key) {
  return get("SELECT value FROM system_config WHERE key=?", [key])?.value || '';
}

/** 是否已配置微信支付 */
function isWechatConfigured() {
  return !!(cfg('wechat_appid') && cfg('wechat_mchid') && cfg('wechat_key'));
}

/** 读取微信支付配置 */
function getWechatConfig() {
  return {
    appid: cfg('wechat_appid'),
    mchId: cfg('wechat_mchid'),
    apiKey: cfg('wechat_key'),
    appSecret: cfg('wechat_appsecret'),
    notifyUrl: cfg('wechat_notify_url') || (cfg('site_url') || 'http://localhost:3001') + '/api/payment/notify',
    certPath: cfg('wechat_cert_path') || '',
    certKeyPath: cfg('wechat_cert_key_path') || '',
  };
}

/**
 * 微信统一下单
 * @param {object} p {tradeNo, amount, description, clientIp, notifyUrl, tradeType, openid}
 */
async function unifiedOrder({ tradeNo, amount, description, clientIp, notifyUrl, tradeType = 'JSAPI', openid = '' }) {
  const conf = getWechatConfig();
  const params = {
    appid: conf.appid,
    mch_id: conf.mchId,
    nonce_str: utils.randomStr(),
    body: description || '商城订单',
    out_trade_no: tradeNo,
    total_fee: utils.amountToFen(amount),
    spbill_create_ip: clientIp || '127.0.0.1',
    notify_url: notifyUrl || conf.notifyUrl,
    trade_type: tradeType,
  };
  if (tradeType === 'JSAPI' && openid) params.openid = openid;
  params.sign = utils.wechatSign(params, conf.apiKey);

  const xml = utils.buildXml('xml', params);
  const resp = await utils.httpsPost(WX_UNIFIED_ORDER, xml, 'text/xml');
  if (resp.status !== 200) throw new Error(`微信统一下单HTTP错误: ${resp.status}`);
  const data = utils.parseXml(resp.data);
  if (data.return_code !== 'SUCCESS') throw new Error(`微信统一下单失败: ${data.return_msg || data.return_code}`);
  if (data.result_code !== 'SUCCESS') throw new Error(`微信统一下单业务失败: ${data.err_code_des || data.err_code}`);
  return {
    prepayId: data.prepay_id,
    codeUrl: data.code_url || '',
    mwebUrl: data.mweb_url || '',
    tradeType: data.trade_type,
  };
}

/** 生成 JSAPI 支付参数 */
function getJsApiParams(prepayId) {
  const conf = getWechatConfig();
  const params = {
    appId: conf.appid,
    timeStamp: String(Math.floor(Date.now() / 1000)),
    nonceStr: utils.randomStr(),
    package: 'prepay_id=' + prepayId,
    signType: 'MD5',
  };
  params.paySign = utils.wechatSign({
    appId: params.appId,
    timeStamp: params.timeStamp,
    nonceStr: params.nonceStr,
    package: params.package,
    signType: params.signType,
  }, conf.apiKey);
  return params;
}

/** NATIVE 扫码支付 URL */
async function getNativePayUrl(tradeNo, amount, description) {
  const r = await unifiedOrder({ tradeNo, amount, description, tradeType: 'NATIVE' });
  return r.codeUrl;
}

/** H5 支付 URL */
async function getH5PayUrl(tradeNo, amount, description, clientIp) {
  const r = await unifiedOrder({ tradeNo, amount, description, clientIp, tradeType: 'MWEB' });
  return r.mwebUrl;
}

/** JSAPI 公众号支付 */
async function createJsapiPay(tradeNo, amount, description, clientIp, openid) {
  const r = await unifiedOrder({ tradeNo, amount, description, clientIp, openid, tradeType: 'JSAPI' });
  return { prepayId: r.prepayId, jsParams: getJsApiParams(r.prepayId), payType: 'jsapi' };
}

/** NATIVE 扫码支付 */
async function createNativePay(tradeNo, amount, description) {
  const codeUrl = await getNativePayUrl(tradeNo, amount, description);
  return { codeUrl, payType: 'native' };
}

/** 微信支付回调验签 */
function verifyNotify(body) {
  const conf = getWechatConfig();
  const data = utils.parseXml(body);
  if (data.return_code !== 'SUCCESS') throw new Error(`微信回调通信失败: ${data.return_msg}`);
  if (data.result_code !== 'SUCCESS') {
    return { success: false, tradeNo: data.out_trade_no, transactionId: data.transaction_id || '', payTime: data.time_end || '', errorMsg: data.err_code_des || '支付失败', raw: data };
  }
  if (!utils.verifyWechatNotify(data, conf.apiKey)) throw new Error('微信支付回调签名验证失败');
  return {
    success: true,
    tradeNo: data.out_trade_no,
    transactionId: data.transaction_id,
    payTime: data.time_end,
    openid: data.openid,
    totalFee: parseInt(data.total_fee) / 100,
    bankType: data.bank_type,
    raw: data,
  };
}

/** 查询订单 */
async function queryOrder(tradeNo) {
  const conf = getWechatConfig();
  const params = {
    appid: conf.appid,
    mch_id: conf.mchId,
    out_trade_no: tradeNo,
    nonce_str: utils.randomStr(),
  };
  params.sign = utils.wechatSign(params, conf.apiKey);
  const xml = utils.buildXml('xml', params);
  const resp = await utils.httpsPost(WX_ORDER_QUERY, xml, 'text/xml');
  if (resp.status !== 200) throw new Error(`微信订单查询HTTP错误: ${resp.status}`);
  const data = utils.parseXml(resp.data);
  if (data.return_code !== 'SUCCESS') throw new Error(`微信订单查询失败: ${data.return_msg}`);
  return {
    tradeState: data.trade_state,
    tradeNo: data.out_trade_no,
    transactionId: data.transaction_id,
    totalFee: parseInt(data.total_fee) / 100,
    payTime: data.time_end || '',
    tradeStateDesc: data.trade_state_desc || '',
  };
}

/** 退款 */
async function refund(tradeNo, refundNo, totalAmount, refundAmount, refundDesc = '') {
  const conf = getWechatConfig();
  const params = {
    appid: conf.appid,
    mch_id: conf.mchId,
    nonce_str: utils.randomStr(),
    out_trade_no: tradeNo,
    out_refund_no: refundNo,
    total_fee: utils.amountToFen(totalAmount),
    refund_fee: utils.amountToFen(refundAmount),
    refund_desc: refundDesc || '用户申请退款',
    notify_url: conf.notifyUrl.replace('/notify', '/refund-notify'),
  };
  params.sign = utils.wechatSign(params, conf.apiKey);
  const xml = utils.buildXml('xml', params);
  const resp = await utils.httpsPostWithCert(WX_REFUND, xml, conf.certPath, conf.certKeyPath);
  if (resp.status !== 200) throw new Error(`微信退款HTTP错误: ${resp.status}`);
  const data = utils.parseXml(resp.data);
  if (data.return_code !== 'SUCCESS') throw new Error(`微信退款请求失败: ${data.return_msg}`);
  if (data.result_code !== 'SUCCESS') throw new Error(`微信退款业务失败: ${data.err_code_des || data.err_code}`);
  return {
    refundId: data.refund_id,
    refundNo: data.out_refund_no,
    refundFee: parseInt(data.refund_fee) / 100,
    totalFee: parseInt(data.total_fee) / 100,
  };
}

/** 查询退款 */
async function queryRefund(refundNo) {
  const conf = getWechatConfig();
  const params = {
    appid: conf.appid,
    mch_id: conf.mchId,
    out_refund_no: refundNo,
    nonce_str: utils.randomStr(),
  };
  params.sign = utils.wechatSign(params, conf.apiKey);
  const xml = utils.buildXml('xml', params);
  const resp = await utils.httpsPost(WX_REFUND_QUERY, xml, 'text/xml');
  if (resp.status !== 200) throw new Error(`微信退款查询HTTP错误: ${resp.status}`);
  const data = utils.parseXml(resp.data);
  if (data.return_code !== 'SUCCESS') throw new Error(`微信退款查询失败: ${data.return_msg}`);
  return {
    refundStatus: data.refund_status_0 || '',
    refundNo: data.out_refund_no,
    refundFee: parseInt(data.refund_fee_0 || 0) / 100,
    totalFee: parseInt(data.total_fee) / 100,
  };
}

/** 下载账单 */
async function downloadBill(billDate, billType = 'ALL') {
  const conf = getWechatConfig();
  const params = {
    appid: conf.appid,
    mch_id: conf.mchId,
    nonce_str: utils.randomStr(),
    bill_date: billDate,
    bill_type: billType,
  };
  params.sign = utils.wechatSign(params, conf.apiKey);
  const xml = utils.buildXml('xml', params);
  const resp = await utils.httpsPost(WX_DOWNLOAD_BILL, xml, 'text/xml');
  if (resp.status !== 200) return null;
  return resp.data;
}

module.exports = {
  isWechatConfigured,
  getWechatConfig,
  unifiedOrder,
  getJsApiParams,
  createJsapiPay,
  createNativePay,
  getH5PayUrl,
  verifyNotify,
  queryOrder,
  refund,
  queryRefund,
  downloadBill,
};
