"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SmallTimerRunner = void 0;
const node_red_1 = require("node-red");
const time_calculation_1 = require("./time-calculation");
class SmallTimerRunner {
    constructor(position, configuration, node) {
        this.node = node;
        this.startupTock = undefined;
        this.tickTimer = undefined;
        this.override = 'auto';
        this.currentState = false;
        this.currentTimeout = 0;
        this.debugMode = false;
        this.timeCalc = new time_calculation_1.TimeCalc(Number(position.latitude), Number(position.longitude), configuration.wrapMidnight, Number(configuration.startTime), Number(configuration.endTime), Number(configuration.startOffset), Number(configuration.endOffset));
        this.topic = configuration.topic;
        this.onMsg = configuration.onMsg;
        this.offMsg = configuration.offMsg;
        this.onMsgType = configuration.onMsgType;
        this.offMsgType = configuration.offMsgType;
        this.rules = configuration.rules;
        this.repeat = configuration.repeat;
        this.debugMode = configuration.debugEnable;
        this.onTimeout = Number(configuration.onTimeout);
        this.offTimeout = Number(configuration.offTimeout);
        if (configuration.injectOnStartup) {
            this.startupTock = setTimeout(this.forceSend.bind(this), 2000);
        }
        else {
            this.calcState();
            this.updateStatus();
        }
        this.startTickTimer();
    }
    getCurrentState() {
        return this.override === 'auto'
            ? this.currentState
            : (this.override === 'tempOn');
    }
    generateDebug() {
        return {
            ...this.timeCalc.debug(),
            override: this.override,
            topic: 'debug'
        };
    }
    generateMsg() {
        const on = this.getCurrentState();
        const payload = on
            ? node_red_1.util.evaluateNodeProperty(this.onMsg, this.onMsgType, this.node, {})
            : node_red_1.util.evaluateNodeProperty(this.offMsg, this.offMsgType, this.node, {});
        return {
            state: this.override,
            stamp: Date.now(),
            autoState: this.override === 'auto',
            duration: 0,
            temporaryManual: this.override !== 'auto',
            timeout: this.currentTimeout,
            payload: payload,
            topic: this.topic,
        };
    }
    publishState() {
        if (this.debugMode) {
            this.node.send([this.generateMsg(), this.generateDebug()]);
        }
        else {
            this.node.send(this.generateMsg());
        }
    }
    isDayOk(date = new Date()) {
        const month = date.getMonth() + 1;
        const dayOfMonth = date.getDate();
        const dayOfWeek = date.getDay();
        const validMonths = [0, month];
        const validDays = [0, dayOfMonth, dayOfWeek + 100];
        let isOk = false;
        this.rules.forEach((item) => {
            const ruleMonth = Number(item.month);
            const ruleDay = Number(item.day);
            if (validMonths.includes(ruleMonth)
                && validDays.includes(ruleDay)) {
                isOk = item.type === 'include';
            }
        });
        return isOk;
    }
    calcState() {
        const date = new Date();
        const newState = this.timeCalc.getOnState(date);
        if ((this.isDayOk(date) || this.currentState) && (newState !== this.currentState)) {
            this.currentState = newState;
            return true;
        }
        return false;
    }
    timerEvent() {
        if (this.currentTimeout > 0) {
            this.currentTimeout -= 1;
            if (this.currentTimeout === 0 && this.override !== 'auto') {
                this.override = 'auto';
            }
        }
        const change = this.calcState();
        this.updateStatus();
        if (change || this.repeat) {
            this.publishState();
        }
    }
    forceSend() {
        this.calcState();
        this.updateStatus();
        this.publishState();
    }
    getHourAndMinutes(time) {
        const minutes = time % 60;
        const hour = Math.floor(time / 60);
        const pad = (n) => n < 10 ? `0${n.toFixed(0)}` : `${n.toFixed(0)}`;
        const hourStr = hour ? `${pad(hour)}hrs ` : '';
        return `${hourStr}${pad(minutes)}mins`;
    }
    updateStatus() {
        let fill = 'yellow';
        const text = [];
        const activeToday = !this.timeCalc.noOnStateToday() && (this.isDayOk() || this.currentState);
        if (!activeToday) {
            text.push('No action today');
        }
        if (this.timeCalc.noOnStateToday()) {
            text.push('off time is before on time');
        }
        if (activeToday || this.override !== 'auto') {
            fill = 'red';
            let state = 'OFF';
            let nextAutoChange = this.timeCalc.getMinutesToNextStartEvent();
            if (this.getCurrentState()) {
                fill = 'green';
                state = 'ON';
                nextAutoChange = this.timeCalc.getMinutesToNextEndEvent();
            }
            const nextTimeoutOrAuto = (this.currentTimeout && this.currentTimeout < nextAutoChange)
                ? this.currentTimeout
                : nextAutoChange;
            const statusText = this.override !== 'auto'
                ? `Temporary ${state} for ${this.getHourAndMinutes(nextTimeoutOrAuto)}`
                : `${state} for ${this.getHourAndMinutes(nextTimeoutOrAuto)}`;
            text.push(statusText);
        }
        const status = {
            fill,
            shape: this.override !== 'auto' ? 'ring' : 'dot',
            text: text.join(' - ')
        };
        this.node.status(status);
    }
    doOverride(override) {
        this.override = override;
        if (override === 'auto') {
            this.currentTimeout = 0;
            return;
        }
        if ((override === 'tempOn') === this.currentState) {
            this.override = 'auto';
            this.currentTimeout = 0;
            return;
        }
        this.currentTimeout = override === 'tempOn'
            ? this.onTimeout
            : this.offTimeout;
    }
    onMessage(incomingMsg) {
        const payload = typeof incomingMsg.payload === 'string'
            ? incomingMsg.payload.toLocaleLowerCase()
            : incomingMsg.payload;
        switch (payload) {
            case 0:
            case '0':
            case 'off':
            case false:
                this.doOverride('tempOff');
                break;
            case 1:
            case '1':
            case 'on':
            case true:
                this.doOverride('tempOn');
                break;
            case 'toggle':
                this.override = ((this.override === 'tempOn') || (this.override === undefined && this.currentState))
                    ? 'tempOff'
                    : 'tempOn';
                break;
            case 'auto':
            case 'default':
                this.doOverride('auto');
                break;
            case 'sync':
                break;
            default:
                return;
        }
        this.forceSend();
    }
    cleanup() {
        if (this.startupTock) {
            clearTimeout(this.startupTock);
        }
        this.stopTickTimer();
    }
    stopTickTimer() {
        if (this.tickTimer) {
            clearInterval(this.tickTimer);
            this.tickTimer = undefined;
        }
    }
    startTickTimer(interval = 60000) {
        if (this.tickTimer === undefined) {
            this.tickTimer = setInterval(this.timerEvent.bind(this), interval);
        }
    }
}
exports.SmallTimerRunner = SmallTimerRunner;
