/**
 * 支付对账与补单服务
 * ============================================
 * 提供三层防护：
 *   1. 主动轮询：支付创建后自动轮询订单状态（60s间隔，最长30分钟）
 *   2. 手动补单：管理员后台手动触发补单
 *   3. 每日对账：自动比对支付记录与订单状态的一致性
 *

 */
const { get, run, all, transaction, getDb } = require('../../utils/db');
const logger = require('./logger');
const paymentSdk = require('./index');
// ===================================================================
// 轮询任务池：记录正在被轮询的订单
// ===================================================================
const pollPool = new Set();
const POLL_INTERVAL = 60 * 1000;    // 60秒轮询一次
const POLL_TIMEOUT = 30 * 60 * 1000; // 最长轮询30分钟
/**
 * 启动订单支付状态轮询
 * @param {string} orderNo - 订单号
 * @param {string} tradeNo - 支付单号
 */
function startPolling(orderNo, tradeNo) {
  const poolKey = `${orderNo}:${tradeNo}`;
  if (pollPool.has(poolKey)) {
    logger.log(tradeNo, 'poll_skip', '已在轮询中', { level: 'debug', orderNo });
    return;
  }
  const startTime = Date.now();
  pollPool.add(poolKey);
  logger.log(tradeNo, 'poll_start', '开始轮询支付状态', { orderNo });
  const interval = setInterval(() => {
    // 超时检查
    if (Date.now() - startTime > POLL_TIMEOUT) {
      clearInterval(interval);
      pollPool.delete(poolKey);
      logger.log(tradeNo, 'poll_timeout', `轮询超时(${POLL_TIMEOUT/1000}s)，停止轮询`, { orderNo, level: 'warn' });
      // 记录超时对账日志
      addReconcileLog({
        orderNo, tradeNo, action: 'auto_poll',
        beforeStatus: 'pending_pay', afterStatus: 'pending_pay',
        result: 'warning', message: '支付状态轮询超时，建议手动补单'
      });
      return;
    }
    // 检查订单状态
    const order = get('SELECT * FROM orders WHERE order_no=?', [orderNo]);
    if (!order) {
      clearInterval(interval);
      pollPool.delete(poolKey);
      return;
    }
    // 订单已支付或已关闭，停止轮询
    if (order.status !== 'pending_pay') {
      clearInterval(interval);
      pollPool.delete(poolKey);
      logger.log(tradeNo, 'poll_done', `订单状态已变更: ${order.status}，停止轮询`, { orderNo });
      return;
    }
    // 查询支付记录状态
    const record = get('SELECT * FROM payment_records WHERE trade_no=?', [tradeNo]);
    if (!record) {
      clearInterval(interval);
      pollPool.delete(poolKey);
      return;
    }
    // 支付记录已成功，但订单未更新
    if (record.status === 'success' && order.status === 'pending_pay') {
      logger.log(tradeNo, 'poll_fix', '检测到支付记录已成功但订单未更新，自动修复', { orderNo, level: 'info' });
      fixOrderStatus(order, record, tradeNo, 'auto_poll');
      clearInterval(interval);
      pollPool.delete(poolKey);
      return;
    }
    // 生产模式下，主动查询支付网关
    if (record.status === 'pending' && !paymentSdk.isSimulateMode()) {
      queryPaymentGateway(tradeNo, record, order)
        .then(fixed => {
          if (fixed) {
            clearInterval(interval);
            pollPool.delete(poolKey);
          }
        })
        .catch(err => {
          logger.log(tradeNo, 'poll_gateway_err', `查询支付网关失败: ${err.message}`, { orderNo, level: 'error' });
        });
    }
  }, POLL_INTERVAL);
}
/**
 * 查询支付网关状态并尝试修复
 */
async function queryPaymentGateway(tradeNo, record, order) {
  try {
    const channel = record.method || 'wechat';
    const result = await paymentSdk.queryTrade(tradeNo, channel);
    
    if (result.status === 'success') {
      logger.log(tradeNo, 'gateway_fix', '支付网关返回成功，自动更新订单状态', { orderNo: order.order_no, level: 'info' });
      fixOrderStatus(order, record, tradeNo, 'auto_poll');
      return true;
    }
    return false;
  } catch (e) {
    return false;
  }
}
/**
 * 修复订单状态（核心逻辑）
 */
function fixOrderStatus(order, record, tradeNo, action) {
  transaction(() => {
    run("UPDATE orders SET status='pending_ship', payment_method=?, paid_amount=?, updated_at=datetime('now','localtime') WHERE id=?",
      [record.method || 'wechat', record.amount, order.id]);
    // 支付成功 -> 尝试创建分销佣金
    try { const commission = require('../../commission'); commission.createCommissionRecords(order.id); } catch(e) {}
    run('INSERT INTO order_logs(order_id, action, content, operator) VALUES(?,?,?,?)',
      [order.id, 'pay', `[补单] 支付成功状态修复，金额: ¥${record.amount}，方式: ${record.method || 'wechat'}，补单操作: ${action}`, 'system']);
    addReconcileLog({
      orderNo: order.order_no, tradeNo, action,
      beforeStatus: 'pending_pay', afterStatus: 'pending_ship',
      result: 'fixed',
      message: `自动修复: 支付记录已成功但订单未更新`
    });
  });
}
/**
 * 写入对账日志
 */
function addReconcileLog({ orderNo, tradeNo, action, beforeStatus, afterStatus, result, message, operator = 'system' }) {
  const order = orderNo ? get('SELECT id FROM orders WHERE order_no=?', [orderNo]) : null;
  run(`INSERT INTO payment_reconciliations(order_id, trade_no, action, before_status, after_status, result, message, operator, created_at)
        VALUES(?,?,?,?,?,?,?,?, datetime('now','localtime'))`,
    [order?.id || null, tradeNo || '', action, beforeStatus || '', afterStatus || '', result, message || '', operator]);
}
// ===================================================================
// 管理端补单 API 调用（供 routes/payment.js 使用）
// ===================================================================
/**
 * 手动补单
 * @param {string} orderNo - 订单号
 * @param {string} operator - 操作人
 * @returns {object} 补单结果
 */
function manualRetry(orderNo, operator) {
  const order = get('SELECT * FROM orders WHERE order_no=?', [orderNo]);
  if (!order) return { success: false, message: '订单不存在' };
  if (order.status === 'pending_ship' || order.status === 'shipped' || order.status === 'received') {
    return { success: true, message: '订单已支付，无需补单', already_paid: true };
  }
  if (order.status !== 'pending_pay') {
    return { success: false, message: `订单当前状态(${order.status})不可补单` };
  }
  // 查找支付记录
  const record = get("SELECT * FROM payment_records WHERE order_id=? ORDER BY id DESC LIMIT 1", [order.id]);
  if (!record) return { success: false, message: '未找到支付记录' };
  // 模拟模式下直接补单
  if (paymentSdk.isSimulateMode()) {
    if (record.status === 'success') {
      fixOrderStatus(order, record, record.trade_no, 'manual_retry');
      return { success: true, message: '补单成功（模拟模式）', mode: 'simulate' };
    }
    return { success: false, message: '模拟模式下该订单未完成支付' };
  }
  // 生产模式：查询支付网关
  return new Promise((resolve) => {
    paymentSdk.queryTrade(record.trade_no, record.method || 'wechat')
      .then(gatewayResult => {
        if (gatewayResult.status === 'success') {
          // 更新支付记录状态
          run("UPDATE payment_records SET status='success', transaction_id=COALESCE(?, transaction_id), pay_time=COALESCE(?, pay_time) WHERE id=?",
            [gatewayResult.transactionId || '', gatewayResult.payTime || '', record.id]);
          const updatedRecord = get('SELECT * FROM payment_records WHERE id=?', [record.id]);
          fixOrderStatus(order, updatedRecord, record.trade_no, 'manual_retry');
          resolve({ success: true, message: '补单成功（生产模式）', mode: 'production' });
        } else {
          resolve({ success: false, message: `支付网关查询: ${gatewayResult.status || '未支付'}` });
        }
      })
      .catch(err => {
        resolve({ success: false, message: `查询支付网关失败: ${err.message}` });
      });
  });
}
/**
 * 每日对账
 * 比对 payment_records 和 orders 的状态一致性
 * @returns {object} 对账结果
 */
function dailyReconcile() {
  const results = {
    total_orders: 0,
    mismatches: [],
    fixes: 0,
    errors: 0,
  };
  // 找到所有支付记录成功但订单未支付的
  const pendingFixes = all(`
    SELECT o.order_no, o.status as order_status, o.id as order_id,
           pr.trade_no, pr.status as pay_status, pr.amount
    FROM payment_records pr
    JOIN orders o ON pr.order_id = o.id
    WHERE pr.status = 'success' AND o.status = 'pending_pay'
  `);
  results.mismatches = pendingFixes.map(r => ({
    order_no: r.order_no,
    issue: '支付记录成功但订单未更新',
    order_status: r.order_status,
    pay_status: r.pay_status,
    amount: r.amount
  }));
  // 自动修复：支付成功但订单未更新
  for (const fix of pendingFixes) {
    try {
      transaction(() => {
        const order = get('SELECT * FROM orders WHERE id=?', [fix.order_id]);
        const record = get('SELECT * FROM payment_records WHERE trade_no=?', [fix.trade_no]);
        if (order && record) {
          fixOrderStatus(order, record, fix.trade_no, 'daily_reconcile');
        }
      });
      results.fixes++;
    } catch (e) {
      results.errors++;
      addReconcileLog({
        orderNo: fix.order_no, tradeNo: fix.trade_no, action: 'daily_reconcile',
        beforeStatus: 'pending_pay', afterStatus: 'pending_pay',
        result: 'error', message: `自动修复失败: ${e.message}`
      });
    }
  }
  // 找到订单已支付但支付记录未成功的（数据异常）
  const reverseMismatches = all(`
    SELECT o.order_no, o.status as order_status, o.paid_amount, o.id as order_id
    FROM orders o
    WHERE o.status IN ('pending_ship','shipped','received','completed')
    AND o.paid_amount > 0
    AND NOT EXISTS (
      SELECT 1 FROM payment_records pr WHERE pr.order_id = o.id AND pr.status = 'success'
    )
  `);
  for (const fix of reverseMismatches) {
    results.mismatches.push({
      order_no: fix.order_no,
      issue: '订单已支付但无成功支付记录',
      order_status: fix.order_status,
      amount: fix.paid_amount
    });
    // 这种不自动修复，仅记录，需要人工确认
    addReconcileLog({
      orderNo: fix.order_no, tradeNo: '', action: 'daily_reconcile',
      beforeStatus: fix.order_status, afterStatus: fix.order_status,
      result: 'warning',
      message: `订单已支付(${fix.order_status})但无对应的成功支付记录，金额: ¥${fix.paid_amount}，需人工确认`
    });
  }
  results.total_orders = pendingFixes.length + reverseMismatches.length;
  return results;
}
/**
 * 查询补单日志列表
 */
function getReconcileLogs(pageNum = 1, pageSize = 20, filters = {}) {
  let where = 'WHERE 1=1';
  const params = [];
  if (filters.result) {
    where += ' AND result=?';
    params.push(filters.result);
  }
  if (filters.action) {
    where += ' AND action=?';
    params.push(filters.action);
  }
  const total = get(`SELECT COUNT(*) as c FROM payment_reconciliations ${where}`, params).c;
  const list = all(`
    SELECT r.*, o.order_no 
    FROM payment_reconciliations r 
    LEFT JOIN orders o ON r.order_id=o.id 
    ${where} 
    ORDER BY r.id DESC 
    LIMIT ? OFFSET ?`,
    [...params, pageSize, (pageNum - 1) * pageSize]
  );
  return { list, total, page: pageNum, pageSize };
}
module.exports = {
  startPolling,
  manualRetry,
  dailyReconcile,
  getReconcileLogs,
  addReconcileLog
};