/**
 * StatusUpdater — periodic Node-RED status badge poller.
 *
 * Replaces the per-node `_statusInterval` boilerplate (e.g. pumpingStation
 * nodeClass lines 160-171) with one class. The adapter constructs it once
 * with a `node` (Node-RED handle) and a `source` (the domain), and the
 * loop drives `node.status(source.getStatusBadge())` at a fixed cadence.
 *
 * Errors thrown from the domain become a red error badge instead of
 * crashing the interval — operators see the failure in the editor.
 *
 * See CONTRACTS.md §7 for the badge shape; statusBadge.js for the helpers.
 */

'use strict';

const { statusBadge } = require('./statusBadge');

const CLEAR_BADGE = {};

class StatusUpdater {
    constructor({ node, source, intervalMs, logger } = {}) {
        if (!node || typeof node.status !== 'function') {
            throw new Error('StatusUpdater: node must expose a .status(badge) method');
        }
        if (!source || typeof source.getStatusBadge !== 'function') {
            throw new Error('StatusUpdater: source must expose a .getStatusBadge() method');
        }
        this._node = node;
        this._source = source;
        this._intervalMs = Number.isFinite(intervalMs) ? intervalMs : 0;
        this._logger = logger || null;
        this._timer = null;
    }

    get isRunning() {
        return this._timer !== null;
    }

    start() {
        // intervalMs=0 keeps unit tests / headless harnesses silent.
        if (this._intervalMs <= 0) return;
        if (this._timer !== null) return;
        this._timer = setInterval(() => this._tick(), this._intervalMs);
    }

    stop() {
        if (this._timer !== null) {
            clearInterval(this._timer);
            this._timer = null;
        }
        // Wipe the badge so a stale label doesn't linger in the editor
        // after the node is closed/redeployed.
        try { this._node.status(CLEAR_BADGE); } catch (_) { /* best effort */ }
    }

    _tick() {
        let badge;
        try {
            badge = this._source.getStatusBadge();
        } catch (err) {
            const msg = err && err.message ? err.message : String(err);
            if (this._logger && typeof this._logger.error === 'function') {
                this._logger.error(`StatusUpdater: getStatusBadge threw: ${msg}`);
            }
            this._safeApply(statusBadge.error(msg));
            return;
        }
        if (badge == null) {
            this._safeApply(CLEAR_BADGE);
            return;
        }
        this._safeApply(badge);
    }

    _safeApply(badge) {
        try {
            this._node.status(badge);
        } catch (err) {
            // node.status itself failing is exotic (e.g. node already
            // closed). Log once per tick; the next tick will retry.
            if (this._logger && typeof this._logger.error === 'function') {
                const msg = err && err.message ? err.message : String(err);
                this._logger.error(`StatusUpdater: node.status threw: ${msg}`);
            }
        }
    }
}

module.exports = { StatusUpdater };
