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

/**
 * Create a device command
 * @param {string} deviceId
 * @param {number} adminId
 * @param {number} opcode
 * @param {Object} payload - will be JSON-stringified
 * @returns {Promise<Array>} query result
 */
async function create(deviceId, adminId, opcode, payload) {
  return query(
    'INSERT INTO device_commands (device_id, admin_id, opcode, payload_json, status) VALUES (:device_id, :admin_id, :opcode, :payload_json, 1)',
    {
      device_id: deviceId,
      admin_id: adminId,
      opcode,
      payload_json: JSON.stringify(payload)
    }
  )
}

/**
 * List commands for a device with pagination
 * @param {string} deviceId
 * @param {Object} opts
 * @param {number} opts.pageSize
 * @param {number} opts.offset
 * @returns {Promise<{records: Array, total: number}>}
 */
async function listByDevice(deviceId, { pageSize, offset }) {
  const total = await query(
    'SELECT COUNT(*) AS total FROM device_commands WHERE device_id = :device_id',
    { device_id: deviceId }
  )
  const records = await query(
    'SELECT command_id, device_id, admin_id, opcode, payload_json, status, created_at, pulled_at, finished_at, result_json FROM device_commands WHERE device_id = :device_id ORDER BY created_at DESC' + limitClause(pageSize, offset),
    { device_id: deviceId }
  )
  return { records, total: total[0].total }
}

/**
 * Count commands for a device
 * @param {string} deviceId
 * @returns {Promise<number>}
 */
async function countByDevice(deviceId) {
  const rows = await query(
    'SELECT COUNT(*) AS total FROM device_commands WHERE device_id = :device_id',
    { device_id: deviceId }
  )
  return rows[0].total
}

/**
 * Get pending commands for a device (status=1), ordered by creation time
 * @param {string} deviceId
 * @returns {Promise<Array>} commands with command_id, opcode, payload_json
 */
async function getPending(deviceId) {
  return query(
    'SELECT command_id, opcode, payload_json FROM device_commands WHERE device_id = :device_id AND status = 1 ORDER BY created_at ASC LIMIT 10',
    { device_id: deviceId }
  )
}

/**
 * Mark commands as pulled (status=2)
 * @param {number[]} commandIds - array of command IDs
 * @returns {Promise<Array>} query result
 */
async function markPulled(commandIds) {
  if (!commandIds || commandIds.length === 0) return []
  return query(
    'UPDATE device_commands SET status = 2, pulled_at = NOW() WHERE command_id IN (' + commandIds.map(Number).join(',') + ')',
    {}
  )
}

/**
 * Finish a command execution (set status=3 success or status=4 failure)
 * @param {number} commandId
 * @param {boolean} success
 * @param {Object} result - result payload to store as JSON
 * @returns {Promise<Array>} query result
 */
async function finish(commandId, success, result) {
  return query(
    'UPDATE device_commands SET status = :status, finished_at = NOW(), result_json = :result_json WHERE command_id = :command_id',
    {
      command_id: commandId,
      status: success ? 3 : 4,
      result_json: JSON.stringify(result)
    }
  )
}

/**
 * Find a command by ID that belongs to a device bound to a specific user
 * @param {number} commandId
 * @param {number} userId
 * @returns {Promise<Object|null>}
 */
async function findByIdForUser(commandId, userId) {
  return one(
    'SELECT dc.command_id FROM device_commands dc JOIN bindings b ON b.device_id = dc.device_id AND b.user_id = :user_id AND b.bind_status = 1 WHERE dc.command_id = :command_id',
    { user_id: userId, command_id: commandId }
  )
}

module.exports = {
  create,
  listByDevice,
  countByDevice,
  getPending,
  markPulled,
  finish,
  findByIdForUser
}
