const { createRequestAuthHeaders } = require('../../request-auth'); function createPlayerActionService(options) { const playerInternalBaseUrl = String(options && options.playerInternalBaseUrl || '').replace(/\/$/, ''); const common = options && options.common; if (!playerInternalBaseUrl || !common) { throw new Error('createPlayerActionService requires the player action dependencies.'); } async function forwardPlayerCommand(slug, commandOrPayload, connectionId) { const payload = typeof commandOrPayload === 'object' && commandOrPayload !== null ? Object.assign({}, commandOrPayload) : { command: commandOrPayload }; if (connectionId) { payload.connectionId = connectionId; } const authHeaders = createRequestAuthHeaders({ method: 'POST', pathname: `/api/screens/${encodeURIComponent(slug)}/commands`, body: payload }); const response = await fetch(`${playerInternalBaseUrl}/api/screens/${encodeURIComponent(slug)}/commands`, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', ...authHeaders }, body: JSON.stringify(payload) }); if (!response.ok) { const errorText = await response.text().catch(function () { return ''; }); const error = new Error(errorText || `Unable to send command to player ${slug}.`); error.statusCode = response.status; throw error; } return response.json().catch(function () { return { ok: true }; }); } async function getScreenConnections(slug) { const authHeaders = createRequestAuthHeaders({ method: 'GET', pathname: `/api/screens/${encodeURIComponent(slug)}/connections` }); const response = await fetch(`${playerInternalBaseUrl}/api/screens/${encodeURIComponent(slug)}/connections`, { method: 'GET', headers: { Accept: 'application/json', ...authHeaders } }); if (!response.ok) { const errorText = await response.text().catch(function () { return ''; }); const error = new Error(errorText || `Unable to load screen connections for ${slug}.`); error.statusCode = response.status; throw error; } return response.json().catch(function () { return { connections: [] }; }); } async function getScreenDeleteBlockMessage(pool, screen, getScreenConnections) { const [rows] = await pool.query('SELECT COUNT(*) AS ref_count FROM player_onboarding_devices WHERE screen_id = ?', [screen.id]); if (Number(rows[0] && rows[0].ref_count) > 0) { return 'This screen is still linked to onboarding devices.'; } if (typeof getScreenConnections === 'function' && String(screen && screen.slug ? screen.slug : '').trim()) { try { const response = await getScreenConnections(screen.slug); const liveConnections = Array.isArray(response && response.connections) ? response.connections : []; if (liveConnections.length > 0) { return 'This screen is still in use by connected players.'; } } catch (_error) { // Keep the delete guard based on onboarding references if live connection lookup fails. } } return ''; } async function getSlideDeleteBlockMessage(pool, slide) { const [rows] = await pool.query('SELECT COUNT(*) AS ref_count FROM playlist_slides WHERE slide_id = ?', [slide.id]); return Number(rows[0] && rows[0].ref_count) > 0 ? 'This slide is still used by one or more playlists.' : ''; } async function getTemplateDeleteBlockMessage(pool, template) { const [rows] = await pool.query('SELECT COUNT(*) AS ref_count FROM slides WHERE template_id = ?', [template.id]); return Number(rows[0] && rows[0].ref_count) > 0 ? 'This template is still used by one or more slides.' : ''; } async function getCanvasSizeDeleteBlockMessage(pool, canvasSize) { const [rows] = await pool.query('SELECT COUNT(*) AS ref_count FROM slide_templates WHERE canvas_size_id = ?', [canvasSize.id]); return Number(rows[0] && rows[0].ref_count) > 0 ? 'This canvas size is still used by one or more templates.' : ''; } async function getPlaylistDeleteBlockMessage(pool, playlist) { const [rows] = await pool.query('SELECT COUNT(*) AS ref_count FROM screens WHERE playlist_id = ?', [playlist.id]); return Number(rows[0] && rows[0].ref_count) > 0 ? 'This playlist is still assigned to one or more screens.' : ''; } return { forwardPlayerCommand: forwardPlayerCommand, getScreenConnections: getScreenConnections, getScreenDeleteBlockMessage: getScreenDeleteBlockMessage, getSlideDeleteBlockMessage: getSlideDeleteBlockMessage, getTemplateDeleteBlockMessage: getTemplateDeleteBlockMessage, getCanvasSizeDeleteBlockMessage: getCanvasSizeDeleteBlockMessage, getPlaylistDeleteBlockMessage: getPlaylistDeleteBlockMessage }; } module.exports = { createPlayerActionService };