const { query, one, transaction } = require('../lib/db')

async function createOrder(orderId, userId, plan, amountFen) {
  return query(
    'INSERT INTO payment_orders (order_id, user_id, plan, amount_fen, status) VALUES (:order_id, :user_id, :plan, :amount_fen, :status)',
    { order_id: orderId, user_id: userId, plan, amount_fen: amountFen, status: 'created' }
  )
}

async function findByOutTradeNo(orderId) {
  return one('SELECT * FROM payment_orders WHERE order_id = :order_id', { order_id: orderId })
}

async function markPrepay(orderId, prepayId) {
  return query(
    'UPDATE payment_orders SET status = :status, prepay_id = :prepay_id WHERE order_id = :order_id AND status = :old_status',
    { order_id: orderId, status: 'paying', prepay_id: prepayId, old_status: 'created' }
  )
}

// Idempotent: only activates if order is not already paid
async function markPaidAndActivateSubscription(orderId, transactionId, rawNotify) {
  const subscriptionDao = require('./subscription.dao')
  return transaction(async conn => {
    const [rows] = await conn.execute(
      'SELECT * FROM payment_orders WHERE order_id = ? AND status != ? FOR UPDATE',
      [orderId, 'paid']
    )
    if (rows.length === 0) return false // already paid or not found
    const order = rows[0]
    if (order.status === 'paid') return false // double check

    await conn.execute(
      'UPDATE payment_orders SET status = ?, transaction_id = ?, trade_state = ?, raw_notify_json = ?, paid_at = NOW() WHERE order_id = ?',
      ['paid', transactionId, 'SUCCESS', JSON.stringify(rawNotify), orderId]
    )

    // Activate subscription using the plan from the order
    const PLAN_DAYS = { monthly: 30, yearly: 365 }
    const days = PLAN_DAYS[order.plan] || 30
    // Use raw conn for the subscription activation within the same transaction
    const [subRows] = await conn.execute(
      'SELECT subscription_id FROM subscriptions WHERE user_id = ? AND status = 1 AND expire_time > NOW() ORDER BY expire_time DESC LIMIT 1',
      [order.user_id]
    )
    if (subRows.length > 0) {
      await conn.execute(
        'UPDATE subscriptions SET expire_time = DATE_ADD(expire_time, INTERVAL ? DAY), plan = ?, amount = amount + ? WHERE subscription_id = ?',
        [days, order.plan, order.amount_fen / 100, subRows[0].subscription_id]
      )
    } else {
      await conn.execute(
        'UPDATE subscriptions SET status = 2 WHERE user_id = ? AND status = 1',
        [order.user_id]
      )
      await conn.execute(
        'INSERT INTO subscriptions (user_id, plan, status, amount, order_id, start_time, expire_time) VALUES (?, ?, 1, ?, ?, NOW(), DATE_ADD(NOW(), INTERVAL ? DAY))',
        [order.user_id, order.plan, order.amount_fen / 100, orderId, days]
      )
    }
    return true
  })
}

async function markClosed(orderId) {
  return query(
    'UPDATE payment_orders SET status = :status, trade_state = :trade_state WHERE order_id = :order_id AND status IN (:s1, :s2)',
    { order_id: orderId, status: 'closed', trade_state: 'CLOSED', s1: 'created', s2: 'paying' }
  )
}

async function markFailed(orderId, tradeState) {
  return query(
    'UPDATE payment_orders SET status = :status, trade_state = :trade_state WHERE order_id = :order_id AND status IN (:s1, :s2)',
    { order_id: orderId, status: 'failed', trade_state: tradeState || 'PAYERROR', s1: 'created', s2: 'paying' }
  )
}

async function countPendingByUser(userId) {
  const rows = await query(
    "SELECT COUNT(*) AS cnt FROM payment_orders WHERE user_id = :user_id AND status IN ('created', 'paying') AND created_at > DATE_SUB(NOW(), INTERVAL 2 HOUR)",
    { user_id: userId }
  )
  return rows[0].cnt
}

async function closeStaleOrders() {
  return query(
    "UPDATE payment_orders SET status = 'closed', trade_state = 'EXPIRED' WHERE status IN ('created', 'paying') AND created_at < DATE_SUB(NOW(), INTERVAL 24 HOUR)"
  )
}

module.exports = { createOrder, findByOutTradeNo, markPrepay, markPaidAndActivateSubscription, markClosed, markFailed, countPendingByUser, closeStaleOrders }
