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

/**
 * List devices with pagination and optional keyword search
 * @param {Object} opts
 * @param {string} [opts.keyword] - search device_id or device_name
 * @param {number} opts.pageSize
 * @param {number} opts.offset
 * @returns {Promise<{records: Array, total: number}>}
 */
async function list({ keyword, pageSize, offset }) {
  let where = ''
  const params = {}
  if (keyword) {
    where = ' WHERE d.device_id LIKE :kw OR d.device_name LIKE :kw'
    params.kw = '%' + keyword + '%'
  }
  const total = await query('SELECT COUNT(*) AS total FROM devices d' + where, params)
  const records = await query(
    'SELECT d.*, b.user_id AS bound_user, b.bind_time AS activated_at FROM devices d LEFT JOIN bindings b ON b.device_id = d.device_id AND b.bind_status = 1' +
    where + ' ORDER BY d.created_at DESC' + limitClause(pageSize, offset),
    params
  )
  return { records, total: total[0].total }
}

/**
 * Count devices matching optional keyword
 * @param {Object} opts
 * @param {string} [opts.keyword]
 * @returns {Promise<number>}
 */
async function count({ keyword }) {
  let where = ''
  const params = {}
  if (keyword) {
    where = ' WHERE d.device_id LIKE :kw OR d.device_name LIKE :kw'
    params.kw = '%' + keyword + '%'
  }
  const rows = await query('SELECT COUNT(*) AS total FROM devices d' + where, params)
  return rows[0].total
}

/**
 * Find a single device by ID with bound user info
 * @param {string} deviceId
 * @returns {Promise<Object|null>}
 */
async function findById(deviceId) {
  return one(
    'SELECT d.*, b.user_id AS bound_user, b.bind_time AS activated_at FROM devices d LEFT JOIN bindings b ON b.device_id = d.device_id AND b.bind_status = 1 WHERE d.device_id = :device_id',
    { device_id: deviceId }
  )
}

/**
 * Find device by ID with binding history and recent treatments
 * @param {string} deviceId
 * @returns {Promise<{device: Object|null, binding_history: Array, recent_treatments: Array}>}
 */
async function findByIdWithHistory(deviceId) {
  const device = await findById(deviceId)
  if (!device) return { device: null, binding_history: [], recent_treatments: [] }
  const bindingHistory = await query(
    'SELECT b.*, u.nickname FROM bindings b LEFT JOIN users u ON u.user_id = b.user_id WHERE b.device_id = :device_id ORDER BY b.bind_time DESC',
    { device_id: deviceId }
  )
  const recentTreatments = await query(
    'SELECT r.*, u.nickname FROM treatment_records r LEFT JOIN users u ON u.user_id = r.user_id WHERE r.device_id = :device_id ORDER BY r.created_at DESC LIMIT 5',
    { device_id: deviceId }
  )
  return { device, binding_history: bindingHistory, recent_treatments: recentTreatments }
}

/**
 * Create or update a device (upsert)
 * @param {Object} device
 * @param {string} device.device_id
 * @param {string} [device.product_id]
 * @param {string} [device.device_secret]
 * @param {string} [device.device_name]
 * @param {string} [device.firmware_version]
 * @returns {Promise<Array>} query result
 */
async function create(device) {
  return query(
    'INSERT INTO devices (device_id, product_id, device_secret, device_name, firmware_version, status) VALUES (:device_id, :product_id, :device_secret, :device_name, :firmware_version, 1) ON DUPLICATE KEY UPDATE product_id = VALUES(product_id), device_secret = VALUES(device_secret), device_name = VALUES(device_name), firmware_version = VALUES(firmware_version), status = 1',
    {
      device_id: device.device_id,
      product_id: device.product_id || 'HOX_LIGHT_MASK',
      device_secret: device.device_secret || '',
      device_name: device.device_name || 'LumiFlow',
      firmware_version: device.firmware_version || '1.0.0'
    }
  )
}

/**
 * Batch-create devices by IDs, return success/failure counts
 * @param {string[]} deviceIds
 * @returns {Promise<{created: number, failed: string[]}>}
 */
async function createBatch(deviceIds) {
  let created = 0
  const failed = []
  for (const id of deviceIds) {
    const deviceId = String(id || '').trim()
    if (!deviceId) { failed.push(id); continue }
    try {
      await create({
        device_id: deviceId,
        product_id: 'HOX_LIGHT_MASK',
        device_secret: '',
        device_name: 'LumiFlow',
        firmware_version: '1.0.0'
      })
      created++
    } catch (err) {
      failed.push(deviceId)
    }
  }
  return { created, failed }
}

/**
 * Admin-unbind a device (set bind_status=2)
 * @param {string} deviceId
 * @returns {Promise<Array>} query result
 */
async function unbind(deviceId) {
  return query(
    'UPDATE bindings SET bind_status = 2, unbind_time = NOW() WHERE device_id = :device_id AND bind_status = 1',
    { device_id: deviceId }
  )
}

/**
 * List user's bound devices with device details
 * @param {number} userId
 * @returns {Promise<Array>}
 */
async function listByUser(userId) {
  return query(
    'SELECT d.device_id, d.device_name, d.status, d.battery, d.firmware_version, d.last_online_at, b.bind_time FROM bindings b JOIN devices d ON d.device_id = b.device_id WHERE b.user_id = :user_id AND b.bind_status = 1 ORDER BY b.bind_time DESC',
    { user_id: userId }
  )
}

/**
 * Get a single bound device for a user
 * @param {number} userId
 * @param {string} deviceId
 * @returns {Promise<Object|null>}
 */
async function findBoundDevice(userId, deviceId) {
  return one(
    'SELECT d.device_id, d.device_name, d.status, d.battery, d.temperature, d.firmware_version, d.last_online_at, b.bind_time FROM bindings b JOIN devices d ON d.device_id = b.device_id WHERE b.user_id = :user_id AND b.bind_status = 1 AND b.device_id = :device_id',
    { user_id: userId, device_id: deviceId }
  )
}

module.exports = {
  list,
  count,
  findById,
  findByIdWithHistory,
  create,
  createBatch,
  unbind,
  listByUser,
  findBoundDevice
}
