const fetch = require("node-fetch");
const process = require('process');
const childProcess = require('child_process');
const moment = require('moment');
const nodeSchedule = require('node-schedule');
const fs = require('fs');
const path = require('path');
const log = require('electron-log');
const {ipcMain} = require('electron');

const getParams = require('./get-params');
const getTimes = require('./scheduler/get-times');
const promiseTimeout = require('./timeout-for-promise');
const buttonsModule = require('./buttons/buttons.js')
const appUpdater = require('../helpers/app-updater');

moment.locale('ru');

let delayUpdateSmartButtons = null;

ipcMain.on('scheduler:update_app', (datetimeSec) => {
    appUpdater.createTaskForInitUpdate(datetimeSec);
});

ipcMain.on('scheduler:update_btn', (datetimeSec) => {
    clearTimeout(delayUpdateSmartButtons);

    delayUpdateSmartButtons = datetimeSec - moment().unix();// seconds

    if ( delayUpdateSmartButtons >= 0 ) {
        log.error('scheduler:update_btn: need update buttons after '+ delayUpdateSmartButtons + ' sec.');
        setTimeout(() => {
            buttonsModule.rebootButtons({});
            log.error('scheduler:update_btn: need update buttons');
        }, delayUpdateSmartButtons * 1000);
    } else {
        log.error('scheduler:update_btn: error get seconds to update');
    }
});

module.exports = async () => {
    try {
        if ( process.platform !== 'linux' ) {
            return log.warn('mod:scheduler()', 'platform not linux');
        }

        log.info('get schedules');

        const {appConfig, savedDataPath} = await getParams('appConfig', 'savedDataPath');

        if ( typeof appConfig !== 'object' || !appConfig.remote_href || !appConfig.device || !appConfig.device._id ) {
            return log.warn('mod:scheduler()', 'bad app config');
        }

        const cancelOldJob = (name) => {
            const jobsList = nodeSchedule.scheduledJobs;
            //
            // jobsList['shutdown-job'].cancel();
            for (const jobName in jobsList) {
                if ( name === jobName ) {
                    jobsList[jobName].cancel();
                    // log.error(jobName, 'CANCELED');
                }
                // log.error('JOB',jobName);
            }
        };

        const href = appConfig.remote_href +'/devices/schedule/'+ appConfig.device._id;
        const schedulesFilePath = path.join(savedDataPath, 'scheduler.json');
        const parseSchedules = function (re) {
            if ( typeof re !== 'object' || !re.schedules || typeof re.schedules !== 'object' ) {
                return log.warn('mod:scheduler()', 'bad json got from: '+ href);
            }

            if ( !fs.existsSync(savedDataPath) ) {
                fs.mkdirSync(savedDataPath);
            }

            /*if ( re.volume ) {
                log.info('need set global volume to: '+ re.volume);
            } else {
                log.info('no global volume');
            }*/

            if ( re.schedules.length > 0 ) {
                for ( let i = 1; i <= 7; i++ ) {
                    log.info(moment().add(i, 'days').weekday());
                }

                const todayWeekDayNumber = moment().weekday();
                let taskWakeup = false;
                let taskShutdown = false;

                cancelOldJob('reboot-job');
                cancelOldJob('shutdown-job');

                re.schedules.forEach((task) => {
                    if ( typeof task !== 'object' || !task.schedule_type || !task.schedule_day_start || !task.schedule_day_end || !task.schedule_time_start || !task.updatedAt  ) {
                        log.error('bad schedule task');
                        return false;
                    }

                    switch ( task.schedule_type ) {
                        case('wakeup'):
                            taskWakeup = task;
                            break;
                        case('reboot'):
                            const reboot = getTimes(task);
                            log.warn('scheduler: reboot on: '+ moment(reboot.nextRunDatetime * 1000).format('DD HH:mm:ss'));
                            nodeSchedule.scheduleJob('reboot-job', moment(reboot.nextRunDatetime * 1000).toDate(), () => childProcess.execFileSync('sudo', ['reboot']));
                            break;
                        case('shutdown'):
                            taskShutdown = task;
                            break;
                        case('update_app'):
                            const updateApp = getTimes(task);
                            let updateAppTask = task;
                            updateAppTask.schedule_time_start = moment(updateAppTask.schedule_time_start, 'HH:mm').add(1, 'hours').format('HH:mm');
                            const updateAppAfter = getTimes(updateAppTask);
                            // log.error(updateApp,' !! ',updateAppAfter);
                            log.warn('scheduler: updateApp on: '+
                             moment(updateAppAfter.nextRunDatetime * 1000).format('DD HH:mm:ss')
                             +' or '+
                             moment(updateApp.nextRunDatetime * 1000).format('DD HH:mm:ss')
                             );
                            ipcMain.emit('scheduler:update_app', updateAppAfter.nextRunDatetime);
                            break;
                        case('update_btn'):
                            const updateButtons = getTimes(task);
                            log.warn('scheduler: updateButtons on: '+ moment(updateButtons.nextRunDatetime * 1000).format('DD HH:mm:ss'));
                            ipcMain.emit('scheduler:update_btn', updateButtons.nextRunDatetime);
                            break;
                    }
                });

                if ( taskWakeup && taskShutdown ) {
                    const now = moment();
                    const wakeupTimes = getTimes(taskWakeup);
                    const taskShutdownTimes = getTimes(taskShutdown);
                    const shutdownAndWakeup = function (wakeupTime) {
                        childProcess.execFileSync('sudo', ['shutdown', '-h', '1']);
                        childProcess.execFileSync('sudo', ['rtcwake', '-m', 'no', '-u', '-t', wakeupTime]);
                    };


                    // log.error('diffs', wakeupTimes.diff, taskShutdownTimes.diff);
                    // log.error('nextRunDatetime', wakeupTimes.nextRunDatetime, taskShutdownTimes.nextRunDatetime);

                    if ( wakeupTimes.diff < taskShutdownTimes.diff ) {
                        if ( wakeupTimes.diff > 300 || !wakeupTimes.allowDays[todayWeekDayNumber] || (taskShutdownTimes.diff < 60 && taskShutdownTimes.allowDays[todayWeekDayNumber]) ) {
                            // shutdown now
                            log.warn('scheduler: shutdown after 1 min and wakeup on: '+ moment(wakeupTimes.nextRunDatetime * 1000).format('DD HH:mm:ss'));
                            shutdownAndWakeup(wakeupTimes.nextRunDatetime);
                        } else {
                            log.warn('scheduler: shutdown on: '+ moment(taskShutdownTimes.nextRunDatetime * 1000).format('DD HH:mm:ss') +' and wakeup on: '+ moment(wakeupTimes.nextRunDatetime * 1000).format('DD HH:mm:ss'));
                            nodeSchedule.scheduleJob('shutdown-job', moment(taskShutdownTimes.nextRunDatetime * 1000).toDate(), () => {
                                shutdownAndWakeup(wakeupTimes.nextRunDatetime);
                            });
                        }
                    } else {
                        if ( taskShutdownTimes.diff < 60 && taskShutdownTimes.allowDays[todayWeekDayNumber] && wakeupTimes.diff > 300 ) {
                            // shutdown now
                            log.warn('scheduler: shutdown after 1 min and wakeup on: '+ moment(wakeupTimes.nextRunDatetime * 1000).format('DD HH:mm:ss'));
                            shutdownAndWakeup(wakeupTimes.nextRunDatetime);
                        } else {
                            log.warn('scheduler: shutdown on: '+ moment(taskShutdownTimes.nextRunDatetime * 1000).format('DD HH:mm:ss') +' and wakeup on: '+ moment(wakeupTimes.nextRunDatetime * 1000).format('DD HH:mm:ss'));
                            nodeSchedule.scheduleJob('shutdown-job', moment(taskShutdownTimes.nextRunDatetime * 1000).toDate(), () => {
                                shutdownAndWakeup(wakeupTimes.nextRunDatetime);
                            });
                        }
                    }
                    // cancelOldJob();
                }

                fs.writeFileSync(schedulesFilePath, JSON.stringify(re));
            } else {
                log.error('no schedules');
            }
        };

        promiseTimeout(fetch(href, {
            cache: 'no-cache'
        }))
            .then(re => re.json())
            .then(re => {
                parseSchedules(re);
            })
            .catch(err => {
                log.error('mod:scheduler() fetch error', err);
            });
    } catch (err) {
        log.error('mod:scheduler() has broken', err);
    }
};
