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

/**
 * Find user by WeChat openid
 * @param {string} openid
 * @returns {Promise<Object|null>}
 */
async function findByOpenid(openid) {
  return one(
    'SELECT * FROM users WHERE openid = :openid',
    { openid }
  )
}

/**
 * Create a new user from WeChat login
 * @param {string} openid
 * @returns {Promise<Object>} query result with insertId
 */
async function create(openid) {
  return query(
    'INSERT INTO users (openid, nickname, avatar, status) VALUES (:openid, :nickname, :avatar, 1)',
    { openid, nickname: '', avatar: '' }
  )
}

/**
 * Find user by user_id
 * @param {number} userId
 * @returns {Promise<Object|null>}
 */
async function findById(userId) {
  return one(
    'SELECT * FROM users WHERE user_id = :user_id',
    { user_id: userId }
  )
}

/**
 * Find active user by user_id (status=1)
 * @param {number} userId
 * @returns {Promise<Object|null>}
 */
async function findActiveById(userId) {
  return one(
    'SELECT * FROM users WHERE user_id = :user_id AND status = 1',
    { user_id: userId }
  )
}

/**
 * Update user profile fields (nickname, avatar, gender)
 * @param {number} userId
 * @param {Object} fields
 * @param {string|null} [fields.nickname]
 * @param {string|null} [fields.avatar]
 * @param {number|null} [fields.gender]
 * @returns {Promise<Array>} query result
 */
async function updateProfile(userId, fields) {
  return query(
    'UPDATE users SET nickname = COALESCE(:nickname, nickname), avatar = COALESCE(:avatar, avatar), gender = COALESCE(:gender, gender) WHERE user_id = :user_id',
    {
      user_id: userId,
      nickname: fields.nickname || null,
      avatar: fields.avatar || null,
      gender: fields.gender === undefined ? null : fields.gender
    }
  )
}

/**
 * Update user phone number
 * @param {number} userId
 * @param {string} phone
 * @returns {Promise<Array>} query result
 */
async function updatePhone(userId, phone) {
  return query(
    'UPDATE users SET phone = :phone WHERE user_id = :user_id',
    { user_id: userId, phone }
  )
}

/**
 * Admin paginated user list with device/treatment/subscription subquery stats
 * @param {Object} opts
 * @param {string} [opts.keyword] - search nickname, phone, or exact user_id
 * @param {number} opts.pageSize
 * @param {number} opts.offset
 * @returns {Promise<{records: Array, total: number}>}
 */
async function listAdmin({ keyword, pageSize, offset }) {
  let where = ''
  const params = {}
  if (keyword) {
    where = ' WHERE u.nickname LIKE :kw OR u.phone LIKE :kw OR u.user_id = :keyword'
    params.kw = '%' + keyword + '%'
    params.keyword = keyword
  }
  const total = await query('SELECT COUNT(*) AS total FROM users u' + where, params)
  const records = await query(
    'SELECT u.*,' +
    ' (SELECT COUNT(*) FROM bindings WHERE user_id = u.user_id AND bind_status = 1) AS device_count,' +
    ' (SELECT COUNT(*) FROM treatment_records WHERE user_id = u.user_id) AS treatment_count,' +
    ' COALESCE((SELECT status FROM subscriptions WHERE user_id = u.user_id AND status = 1 AND expire_time > NOW() ORDER BY expire_time DESC LIMIT 1), 0) AS subscription_status' +
    ' FROM users u' + where + ' ORDER BY u.created_at DESC' + limitClause(pageSize, offset),
    params
  )
  return { records, total: total[0].total }
}

/**
 * Count admin users with optional keyword
 * @param {Object} opts
 * @param {string} [opts.keyword]
 * @returns {Promise<number>}
 */
async function countAdmin({ keyword }) {
  let where = ''
  const params = {}
  if (keyword) {
    where = ' WHERE u.nickname LIKE :kw OR u.phone LIKE :kw OR u.user_id = :keyword'
    params.kw = '%' + keyword + '%'
    params.keyword = keyword
  }
  const rows = await query('SELECT COUNT(*) AS total FROM users u' + where, params)
  return rows[0].total
}

/**
 * Admin detail view: user + bound devices, recent treatments, subscription, stats
 * @param {number} userId
 * @returns {Promise<Object|null>} enriched user object or null
 */
async function findByIdAdmin(userId) {
  const user = await one('SELECT * FROM users WHERE user_id = :user_id', { user_id: userId })
  if (!user) return null

  const devices = await query(
    'SELECT d.device_id, d.device_name FROM bindings b JOIN devices d ON d.device_id = b.device_id WHERE b.user_id = :user_id AND b.bind_status = 1',
    { user_id: userId }
  )
  const treatments = await query(
    'SELECT * FROM treatment_records WHERE user_id = :user_id ORDER BY created_at DESC LIMIT 5',
    { user_id: userId }
  )
  const subscription = await one(
    'SELECT plan, status, start_time, expire_time FROM subscriptions WHERE user_id = :user_id AND status = 1 AND expire_time > NOW() ORDER BY expire_time DESC LIMIT 1',
    { user_id: userId }
  )
  const stats = await one(
    'SELECT COUNT(*) AS treatment_count, COALESCE(SUM(total_duration_ms), 0) AS total_duration FROM treatment_records WHERE user_id = :user_id',
    { user_id: userId }
  )

  return Object.assign({}, user, {
    devices,
    recent_treatments: treatments,
    subscription_status: subscription ? subscription.status : 0,
    subscription_type: subscription ? subscription.plan : null,
    subscription_expire: subscription ? subscription.expire_time : null,
    treatment_count: stats ? stats.treatment_count : 0,
    total_duration: stats ? stats.total_duration : 0
  })
}

/**
 * Update user status.
 * @param {number} userId
 * @param {number} status - 1=active, 2=disabled, 3=cancelled
 * @returns {Promise<Array>} query result
 */
async function updateStatus(userId, status) {
  return query(
    'UPDATE users SET status = :status WHERE user_id = :user_id',
    { user_id: userId, status }
  )
}

/**
 * Soft-cancel a user account and unbind all active devices.
 * Historical treatment/subscription/log rows are kept.
 * @param {number} userId
 * @returns {Promise<{userAffectedRows: number, unboundRows: number}>}
 */
async function deactivate(userId) {
  return transaction(async conn => {
    const [userResult] = await conn.execute(
      'UPDATE users SET status = 3 WHERE user_id = ? AND status <> 3',
      [userId]
    )
    const [unbindResult] = await conn.execute(
      'UPDATE bindings SET bind_status = 2, unbind_time = NOW() WHERE user_id = ? AND bind_status = 1',
      [userId]
    )
    return {
      userAffectedRows: userResult.affectedRows || 0,
      unboundRows: unbindResult.affectedRows || 0
    }
  })
}

module.exports = {
  findByOpenid,
  create,
  findById,
  findActiveById,
  updateProfile,
  updatePhone,
  listAdmin,
  countAdmin,
  findByIdAdmin,
  updateStatus,
  deactivate
}
