const storage = require("Storage");
const heatshrink = require("heatshrink");

exports.STATE_PATH = "pomoplus.state.json";
exports.SETTINGS_PATH = "pomoplus.json";

exports.PHASE_WORKING = 0;
exports.PHASE_SHORT_BREAK = 1;
exports.PHASE_LONG_BREAK = 2;

exports.BUTTON_ICONS = {
    play: heatshrink.decompress(atob("jEYwMAkAGBnACBnwCBn+AAQPgAQPwAQP8AQP/AQXAAQPwAQP8AQP+AQgICBwQUCEAn4FggyBHAQ+CIgQ")),
    pause: heatshrink.decompress(atob("jEYwMA/4BBAX4CEA")),
    reset: heatshrink.decompress(atob("jEYwMA/4BB/+BAQPDAQPnAQIAKv///0///8j///EP//wAQQICBwQUCEhgyCHAQ+CIgI=")),
    skip: heatshrink.decompress(atob("jEYwMAwEIgHAhkA8EOgHwh8A/EPwH8h/A/0P8H/h/w/+P/H/5/8//v/3/AAoICBwQUCDQIgCEwQsCGQQ4CHwRECA"))
};

exports.settings = storage.readJSON(exports.SETTINGS_PATH);
if (!exports.settings) {
    exports.settings = {
        workTime: 1500000,                  //Work for 25 minutes
        shortBreak: 300000,                 //5 minute short break
        longBreak: 900000,                  //15 minute long break
        numShortBreaks: 3,                  //3 short breaks for every long break
        pausedTimerExpireTime: 21600000,    //If the timer was left paused for >6 hours, reset it on next launch
        widget: false,                       //If a widget is added in the future, whether the user wants it
        notifyShortPattern: "=",            // pattern for short break notification
        notifyLongPattern: "=",             // pattern for long break notification
        notifyWorkPattern: "==",            // pattern for work session notification
        notifyReps: 2,                      // number of pattern repetitions
        notifyRepsDelay: 50,                // delay between repetitions (in ms)
    };
}

//Store the minimal amount of information to be able to reconstruct the state of the timer at any given time.
//This is necessary because it is necessary to write to flash to let the timer run in the background, so minimizing the writes is necessary.
exports.STATE_DEFAULT = {
    wasRunning: false,              //If the timer ever was running. Used to determine whether to display a reset button
    running: false,                 //Whether the timer is currently running
    startTime: 0,                   //When the timer was last started. Difference between this and now is how long timer has run continuously.
    pausedTime: 0,                  //When the timer was last paused. Used for expiration and displaying timer while paused.
    elapsedTime: 0,                 //How much time the timer had spent running before the current start time. Update on pause or user skipping stages.
    phase: exports.PHASE_WORKING,   //What phase the timer is currently in
    numShortBreaks: 0               //Number of short breaks that have occured so far
};
exports.state = storage.readJSON(exports.STATE_PATH);
if (!exports.state) {
    exports.state = exports.STATE_DEFAULT;
}

//Get the number of milliseconds until the next phase change
exports.getTimeLeft = function () {
    if (!exports.state.wasRunning) {
        //If the timer never ran, the time left is just the amount of work time.
        return exports.settings.workTime;
    } else if (exports.state.running) {
        //If the timer is running, the time left is current time - start time + preexisting time
        var runningTime = (new Date()).getTime() - exports.state.startTime + exports.state.elapsedTime;
    } else {
        //If the timer is not running, the same as above but use when the timer was paused instead of now.
        var runningTime = exports.state.pausedTime - exports.state.startTime + exports.state.elapsedTime;
    }

    if (exports.state.phase == exports.PHASE_WORKING) {
        return exports.settings.workTime - runningTime;
    } else if (exports.state.phase == exports.PHASE_SHORT_BREAK) {
        return exports.settings.shortBreak - runningTime;
    } else {
        return exports.settings.longBreak - runningTime;
    }
}

//Get the next phase to change to
exports.getNextPhase = function () {
    if (exports.state.phase == exports.PHASE_WORKING) {
        if (exports.state.numShortBreaks < exports.settings.numShortBreaks) {
            return exports.PHASE_SHORT_BREAK;
        } else {
            return exports.PHASE_LONG_BREAK;
        }
    } else {
        return exports.PHASE_WORKING;
    }
}

//Change to the next phase and update numShortBreaks, and optionally vibrate. DOES NOT WRITE STATE CHANGE TO STORAGE!
exports.nextPhase = function (vibrate) {
    let now = (new Date()).getTime();
    exports.state.startTime = now;  //The timer is being reset, so say it starts now.
    exports.state.pausedTime = now; //This prevents a paused timer from having the start time moved to the future and therefore having been run for negative time.
    exports.state.elapsedTime = 0;  //Because we are resetting the timer, we no longer need to care about whether it was paused previously.

    let oldPhase = exports.state.phase; //Cache the old phase because we need to remember it when counting the number of short breaks
    exports.state.phase = exports.getNextPhase();

    if (oldPhase == exports.PHASE_SHORT_BREAK) {
        //If we just left a short break, increase the number of short breaks
        exports.state.numShortBreaks++;
    } else if (oldPhase == exports.PHASE_LONG_BREAK) {
        //If we just left a long break, set the number of short breaks to zero
        exports.state.numShortBreaks = 0;
    }

    if (vibrate) {
        if (exports.state.phase == exports.PHASE_WORKING) {
            exports.doNotify(exports.settings.notifyWorkPattern, exports.settings.notifyReps,exports.settings.notifyRepsDelay);  

        } else if (exports.state.phase == exports.PHASE_SHORT_BREAK) {
            exports.doNotify(exports.settings.notifyShortPattern, exports.settings.notifyReps,exports.settings.notifyRepsDelay);  
      
        } else {
            exports.doNotify(exports.settings.notifyLongPattern, exports.settings.notifyReps,exports.settings.notifyRepsDelay);  
        }
    }
}

exports.doNotify = function(pattern, repetitions, repeatDelay) {
    const buzz = require("buzz");

    let i = 0;

    function doBuzz() {
      buzz.pattern(pattern).then(() => {
        i++;
        if (i < repetitions) {
          setTimeout(doBuzz, repeatDelay);
        }
      });
    }

    doBuzz();
}
