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

/**
 * Find active subscription for a user with remaining days
 * @param {number} userId
 * @returns {Promise<Object|null>} subscription row with remaining_days, or null
 */
async function findActive(userId) {
  return one(
    'SELECT *, GREATEST(DATEDIFF(expire_time, NOW()), 0) AS remaining_days FROM subscriptions WHERE user_id = :user_id AND status = 1 AND expire_time > NOW() ORDER BY expire_time DESC LIMIT 1',
    { user_id: userId }
  )
}

/**
 * Find active subscription summary (plan + remaining_days) for a user
 * @param {number} userId
 * @returns {Promise<Object|null>}
 */
async function findActiveSummary(userId) {
  return one(
    'SELECT plan, GREATEST(DATEDIFF(expire_time, NOW()), 0) AS remaining_days FROM subscriptions WHERE user_id = :user_id AND status = 1 AND expire_time > NOW() ORDER BY expire_time DESC LIMIT 1',
    { user_id: userId }
  )
}

/**
 * Check if a user has ever had a trial subscription
 * @param {number} userId
 * @returns {Promise<Object|null>} subscription row or null
 */
async function findTrial(userId) {
  return one(
    "SELECT subscription_id FROM subscriptions WHERE user_id = :user_id AND plan = 'trial' LIMIT 1",
    { user_id: userId }
  )
}

/**
 * Check if a user has any active subscription
 * @param {number} userId
 * @returns {Promise<Object|null>}
 */
async function findAnyActive(userId) {
  return one(
    'SELECT subscription_id FROM subscriptions WHERE user_id = :user_id AND status = 1 LIMIT 1',
    { user_id: userId }
  )
}

/**
 * Create a trial subscription (configurable days, amount=0)
 * @param {number} userId
 * @param {string} [orderId] - optional order ID
 * @param {number} [days] - trial duration in days (default 7)
 * @returns {Promise<Array>} query result
 */
async function createTrial(userId, orderId, days) {
  const trialDays = Number(days) || 7
  return query(
    "INSERT INTO subscriptions (user_id, plan, status, amount, order_id, start_time, expire_time) VALUES (:user_id, 'trial', 1, 0, :order_id, NOW(), DATE_ADD(NOW(), INTERVAL :trial_days DAY))",
    { user_id: userId, order_id: orderId || 'TRIAL' + Date.now(), trial_days: trialDays }
  )
}

/**
 * Grant trial if user is eligible (never had trial before, no active sub).
 * Designed to be called within an existing transaction with a connection.
 * Uses SELECT FOR UPDATE to prevent race conditions.
 * @param {number} userId
 * @param {Object} conn - transaction connection
 * @param {number} [days] - trial days (default 7)
 * @returns {Promise<boolean>} true if trial was granted
 */
async function grantTrialIfEligible(userId, conn, days) {
  const trialDays = Number(days) || 7
  const [activeSubs] = await conn.execute(
    'SELECT subscription_id FROM subscriptions WHERE user_id = ? AND status = 1 AND expire_time > NOW() LIMIT 1 FOR UPDATE',
    [userId]
  )
  if (activeSubs.length > 0) return false
  const [trialHistory] = await conn.execute(
    "SELECT subscription_id FROM subscriptions WHERE user_id = ? AND plan = 'trial' LIMIT 1 FOR UPDATE",
    [userId]
  )
  if (trialHistory.length > 0) return false
  await conn.execute(
    "INSERT INTO subscriptions (user_id, plan, status, amount, start_time, expire_time) VALUES (?, 'trial', 1, 0, NOW(), DATE_ADD(NOW(), INTERVAL ? DAY))",
    [userId, trialDays]
  )
  return true
}

/**
 * Purchase / activate a subscription: extend existing or create new
 * If user has an active subscription, add days to current expire_time.
 * If no active subscription, insert a new one starting NOW().
 * @param {number} userId
 * @param {string} plan - 'monthly' | 'yearly' | 'trial'
 * @param {number} amount
 * @param {string} orderId
 * @param {number} days
 * @returns {Promise<void>}
 */
async function purchase(userId, plan, amount, orderId, days) {
  return transaction(async conn => {
    const [rows] = 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',
      [userId]
    )
    if (rows.length > 0) {
      // Extend existing active subscription
      await conn.execute(
        'UPDATE subscriptions SET expire_time = DATE_ADD(expire_time, INTERVAL ? DAY), plan = ?, amount = amount + ? WHERE subscription_id = ?',
        [days, plan, amount, rows[0].subscription_id]
      )
    } else {
      // Expire any stale rows (status=1 but already past expire_time), then insert new
      await conn.execute(
        'UPDATE subscriptions SET status = 2 WHERE user_id = ? AND status = 1',
        [userId]
      )
      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))',
        [userId, plan, amount, orderId, days]
      )
    }
  })
}

/**
 * Admin-create a subscription: extend existing or create new (transactional)
 * If user has an active subscription, add days to current expire_time.
 * If no active subscription, insert a new one starting NOW().
 * @param {number} userId
 * @param {string} plan
 * @param {number} amount
 * @param {string} orderId
 * @param {number} days
 * @returns {Promise<void>}
 */
async function adminCreate(userId, plan, amount, orderId, days) {
  return transaction(async conn => {
    const [rows] = 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',
      [userId]
    )
    if (rows.length > 0) {
      // Extend existing active subscription
      await conn.execute(
        'UPDATE subscriptions SET expire_time = DATE_ADD(expire_time, INTERVAL ? DAY), plan = ?, amount = amount + ? WHERE subscription_id = ?',
        [days, plan, amount, rows[0].subscription_id]
      )
    } else {
      // Expire any stale rows, then insert new
      await conn.execute(
        'UPDATE subscriptions SET status = 2 WHERE user_id = ? AND status = 1',
        [userId]
      )
      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))',
        [userId, plan, amount, orderId, days]
      )
    }
  })
}

/**
 * Cancel a subscription (set status=3)
 * @param {number} subscriptionId
 * @returns {Promise<Array>} query result (check affectedRows)
 */
async function cancel(subscriptionId) {
  return query(
    'UPDATE subscriptions SET status = 3 WHERE subscription_id = :subscription_id AND status = 1',
    { subscription_id: subscriptionId }
  )
}

/**
 * Admin paginated subscription list with user nickname and optional tab filter
 * @param {Object} opts
 * @param {string} [opts.tab] - 'all' | 'monthly' | 'yearly' | 'trial' | 'expired'
 * @param {number} opts.pageSize
 * @param {number} opts.offset
 * @returns {Promise<{records: Array, total: number}>}
 */
async function list({ tab, pageSize, offset }) {
  let where = ''
  const params = {}
  if (tab && tab !== 'all') {
    if (tab === 'expired') {
      where = ' WHERE s.status = 2'
    } else {
      where = ' WHERE s.plan = :plan'
      params.plan = tab
    }
  }
  const total = await query('SELECT COUNT(*) AS total FROM subscriptions s' + where, params)
  const records = await query(
    'SELECT s.*, u.nickname FROM subscriptions s LEFT JOIN users u ON u.user_id = s.user_id' +
    where + ' ORDER BY s.created_at DESC' + limitClause(pageSize, offset),
    params
  )
  return { records, total: total[0].total }
}

/**
 * Count subscriptions with optional tab filter
 * @param {Object} opts
 * @param {string} [opts.tab]
 * @returns {Promise<number>}
 */
async function count({ tab }) {
  let where = ''
  const params = {}
  if (tab && tab !== 'all') {
    if (tab === 'expired') {
      where = ' WHERE s.status = 2'
    } else {
      where = ' WHERE s.plan = :plan'
      params.plan = tab
    }
  }
  const rows = await query('SELECT COUNT(*) AS total FROM subscriptions s' + where, params)
  return rows[0].total
}

/**
 * Get subscription stats: plan counts + monthly revenue
 * @returns {Promise<Object>} { monthly_count, yearly_count, trial_count, monthly_revenue }
 */
async function getStats() {
  const rows = await query(
    'SELECT ' +
    "SUM(CASE WHEN plan = 'monthly' AND status = 1 AND expire_time > NOW() THEN 1 ELSE 0 END) AS monthly_count, " +
    "SUM(CASE WHEN plan = 'yearly' AND status = 1 AND expire_time > NOW() THEN 1 ELSE 0 END) AS yearly_count, " +
    "SUM(CASE WHEN plan = 'trial' AND status = 1 AND expire_time > NOW() THEN 1 ELSE 0 END) AS trial_count, " +
    'COALESCE(SUM(CASE WHEN MONTH(start_time) = MONTH(NOW()) AND YEAR(start_time) = YEAR(NOW()) THEN amount ELSE 0 END), 0) AS monthly_revenue ' +
    'FROM subscriptions',
    {}
  )
  return rows[0] || {}
}

module.exports = {
  findActive,
  findActiveSummary,
  findTrial,
  findAnyActive,
  createTrial,
  grantTrialIfEligible,
  purchase,
  adminCreate,
  cancel,
  list,
  count,
  getStats
}
