var Clay = require('pebble-clay');
var clayConfig = require('./config');
var clay = new Clay(clayConfig);
const jsSHA = require('./sha');

var messageKeys = require('message_keys');

var sid;
var status;
var retry;
retry = 0;


function dec2hex(s) {
    return (s < 15.5 ? '0' : '') + Math.round(s).toString(16);
}

function hex2dec(s) {
    return parseInt(s, 16);
}

function base32tohex(base32) {
    var base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
    var bits = "";
    var hex = "";

    for (var i = 0; i < base32.length; i++) {
        var val = base32chars.indexOf(base32.charAt(i).toUpperCase());
        bits += leftpad(val.toString(2), 5, '0');
    }
    //console.log('-- bits : ' + bits)

    for (var i = 0; i + 4 <= bits.length; i += 4) {
        var chunk = bits.substring(i, i + 4);
        hex = hex + parseInt(chunk, 2).toString(16);
    }
    return hex;

}

function leftpad(str, len, pad) {
    if (len + 1 >= str.length) {
        str = Array(len + 1 - str.length).join(pad) + str;
    }
    return str;
}

function getOtp() {
    key = base32tohex(JSON.parse(localStorage.getItem('clay-settings')).OTP_seed)
    //console.log('-- seed:' + JSON.parse(localStorage.getItem('clay-settings')).OTP_seed)
    //console.log('-- key:' + key)
    var epoch = Math.round(new Date().getTime() / 1000.0);
    if ((30 - (epoch % 30)) < 10) {
        console.log('------- waiting for new TOTP,' + epoch);
        return false;
    } else {
        var time = leftpad(dec2hex(Math.floor(epoch / 30)), 16, '0');
        // updated for jsSHA v2.0.0 - http://caligatio.github.io/jsSHA/
        var shaObj = new jsSHA("SHA-1", "HEX");
        shaObj.setHMACKey(key, "HEX");
        shaObj.update(time);
        var hmac = shaObj.getHMAC("HEX");
        //console.log('-- hmac:' + hmac)
        var offset = hex2dec(hmac.substring(hmac.length - 1));
        //console.log('--offset:' + offset)
        var otp = (hex2dec(hmac.substring(offset * 2, offset * 2 + 8)) & hex2dec('7fffffff')) + '';
        otp = (otp).substring(otp.length - 6, otp.length);
        console.log('------- TOTP ' + otp + ' is expiring in ' + (30 - (epoch % 30)));
        return otp
    }
}

function xhr_to_syno(method, url_path, onload_function, max_retry, timeout) {
    console.log('------xhr start')
    status = "";
    if (JSON.parse(localStorage.getItem('clay-settings')).server) {
        var server = JSON.parse(localStorage.getItem('clay-settings')).server
        url = server + url_path;
        var xhr = new XMLHttpRequest();
        xhr.timeout = timeout; // time in milliseconds

        xhr.open(method, url, true);
        console.log('------xhr opened')
        xhr.onreadystatechange = function () {
            console.log('------xhr onreadystatechange')
            if (xhr.readyState === 4) {
                retry = 0;
                console.log('------xhr readyState 4');
                if (xhr.status == 200) {
                    console.log('------xhr status 200 ');
                    onload_function(xhr);
                    return true;
                } else if (xhr.status == 407) { //blocked by proxy (and syno Firewall too)
                    console.log('------xhr status 407 blocked by proxy (and syno Firewall too) ');
                    onload_function(xhr);
                    return false;
                } else if (xhr.status >= 400) { //wrong credentials
                    console.log('------xhr status 401 wrong credentials ');
                    onload_function(xhr);
                    return false;
                } else if (xhr.status == 0) { //timeout
                    retry++;
                    if (retry < max_retry) {
                        console.log('------xhr timed out retrying another time ');
                        //send back "timeout" to watch
                        message = "Time out (" + retry + "), retrying...";

                        // Build message
                        var dict = {
                            'status': message,
                        };

                        // Send the message
                        Pebble.sendAppMessage(dict, function (e) {
                            console.log('sent');
                        }, function () {
                            console.log('failed');
                        });

                        setTimeout(function () { xhr_to_syno(method, url_path, onload_function, max_retry, timeout) }, 60000 * retry);
                    } else {
                        console.log('------xhr timed out ' + retry + ' times');
                        //send back "timeout" to watch
                        message = "Time out " + retry + " times, verify settings and connectivity";

                        // Build message
                        var dict = {
                            'status': message,
                        };

                        // Send the message
                        Pebble.sendAppMessage(dict, function (e) {
                            console.log('sent');
                        }, function () {
                            console.log('failed');
                        });
                        return false;
                    }
                } else { //timeout ?
                    console.log('------xhr request returned error code ' + xhr.status);
                    message = "Error (XHR" + xhr.status + ")";
                    // Build message
                    var dict = {
                        'status': message,
                    };

                    // Send the message
                    Pebble.sendAppMessage(dict, function (e) {
                        console.log('sent');
                    }, function () {
                        console.log('failed');
                    });
                    return false;
                }
            } else {
                console.log('------xhr readyState ' + xhr.readyState);

            }
        };

        xhr.ontimeout = function (e) {

        };
        xhr.send(null);

    } else {
        Pebble.showSimpleNotificationOnPebble("DSCam H-S", "You need to set your Synology account and server.");
    }

}


function authenticate() {
    var response;
    sid = "";
    console.log('---- authenticate');
    if (JSON.parse(localStorage.getItem('clay-settings')).username && JSON.parse(localStorage.getItem('clay-settings')).password) {
        var username = JSON.parse(localStorage.getItem('clay-settings')).username;
        var password = JSON.parse(localStorage.getItem('clay-settings')).password;
        console.log('-- username:' + username);
        console.log('-- password:' + password.substring(0, 1) + '...');
        var url_path = "/webapi/auth.cgi?api=SYNO.API.Auth&method=Login&version=6&account=" + username + "&passwd=" + password + "&session=SurveillanceStation&format=sid";
        if (JSON.parse(localStorage.getItem('clay-settings')).OTP_enabled) {
            var otp_code = getOtp()
            if (!otp_code) {
                return false
            }
            console.log('-- otp_code is :' + otp_code)
            url_path = url_path + "&otp_code=" + otp_code
        }
        var method = "GET";
        onload_function = function (xhr) {
            response = JSON.parse(xhr.responseText);
            if (response.success == true) {
                sid = response.data.sid;
                console.log('------Authentication succeeded');
                if (sid != "") {
                    message = "Welcome to Syno Cam Switch ! ready & authenticated";
                    // Build message
                    var dict = {
                        'auth': message,
                    };
                    // Send the message
                    Pebble.sendAppMessage(dict, function (e) {
                        console.log('sent');
                    }, function () {
                        console.log('failed');
                    });
                    timed_switch_home(15 * 60);
                } else {
                    console.log('------Unexpected error : authentication is OK but no SID retrieved');
                    message = "Auth error, no SID";
                    // Build message
                    var dict = {
                        'auth': message,
                    };
                    // Send the message
                    Pebble.sendAppMessage(dict, function (e) {
                        console.log('sent');
                    }, function () {
                        console.log('failed');
                    });
                }
            } else {
                console.log('------Authentication failed : ' + JSON.stringify(response));
                if (response.error.code == 400) {
                    console.log('------Authentication failed because of wrong creds');
                    message = "Authentication failed, check your credentials";
                } else if (response.error.code == 404) {
                    console.log('------Authentication failed because of wrong TOTP');
                    message = "Authentication failed, check your TOTP seed";
                }
                // Build message
                var dict = {
                    'auth': message,
                };
                // Send the message
                Pebble.sendAppMessage(dict, function (e) {
                    console.log('sent');
                }, function () {
                    console.log('failed');
                });
            }
        };
        max_retry = 1;
        xhr_to_syno(method, url_path, onload_function, max_retry, 20000);
    } else {
        console.log("--- failed to get settings");
        Pebble.showSimpleNotificationOnPebble("DSCam H-S", "You need to set your Synology account and server.");
    }
    return true


}


function get_status() {
    var response;

    if (sid != "") {
        status = "";
        console.log('---- get_status');

        var url_path = "/webapi/entry.cgi?api=SYNO.SurveillanceStation.HomeMode&version=1&method=GetInfo&_sid=" + sid;
        var method = "GET";

        onload_function = function (xhr) {
            response = JSON.parse(xhr.responseText);
            if (response.success == true) {
                status = response.data.on;
                var message;
                switch (status) {
                    case true:
                        message = "Home mode is ON (camera is off)";
                        break;
                    case false:
                        message = "Home mode is OFF (camera is on)";
                        break;
                    default:
                        message = "something happened, try again ! (IMPOSSIBLE)";
                }
            } else {
                message = "something happened, try again ! (G200)";
            }
            // Build message
            var dict = {
                'status': message,
            };

            // Send the message
            Pebble.sendAppMessage(dict, function (e) {
                console.log('sent');
            }, function () {
                console.log('failed');
            });
        }

        max_retry = 10;
        xhr_to_syno(method, url_path, onload_function, max_retry, 10000);

    } else {
        authenticate();        
        get_status();
    }

}


function timed_switch_home(duration) {
    var response;
    console.log('---- timed switch');
    if (sid != "") {
        var epoch = Math.round(new Date().getTime() / 1000.0);
        var start_ts = epoch + 10
        var end_ts = duration + start_ts
        var d = new Date(end_ts * 1000)
        var end_time = d.toLocaleTimeString("fr-FR",{timestyle:'short'});
        console.log('---- switching home mode for ' + duration + 'seconds, until ' + end_time);
        url_path = "/webapi/entry.cgi?api=SYNO.SurveillanceStation.HomeMode&version=1&method=SaveOneTimeSwitch&onetime_enable_on=true&onetime_disable_on=true&onetime_enable_time=" + start_ts + "&onetime_disable_time=" + end_ts + "&_sid=" + sid;
        method = "GET"
        onload_switch_function = function (xhr) {
            response = JSON.parse(xhr.responseText);
            if (response.success == true) {
                message = "Home mode is ON until " + end_time;
            } else {
                message = "something happened, try again ! (S200)";
                console.log('---- ' + message + ' ' + xhr.responseText)
            }
            // Build message
            dict = {
                'status': message,
            };

            // Send the message Home mode is ON for 900 seconds
            Pebble.sendAppMessage(dict, function (e) {
                console.log('sent \"' + message + '\"');
            }, function () {
                console.log('failed');
            });
        }
        max_retry = 10;
        xhr_to_syno(method, url_path, onload_switch_function, max_retry, 10000);


    } else {
        authenticate();
        timed_switch_home(duration)
    }

}

function switch_home(bool) {
    var response;
    if (sid != "") {
        console.log('---- switching home mode to ' + bool);
        var epoch = Math.round(new Date().getTime() / 1000.0);
        var start_ts = epoch + 10
        switch (bool) {
            case true:
                url_path = "/webapi/entry.cgi?api=SYNO.SurveillanceStation.HomeMode&version=1&method=SaveOneTimeSwitch&onetime_enable_on=true&onetime_disable_on=false&onetime_enable_time=" + start_ts + "&_sid=" + sid;
                break;
            case false:
                url_path = "/webapi/entry.cgi?api=SYNO.SurveillanceStation.HomeMode&version=1&method=SaveOneTimeSwitch&onetime_enable_on=false&onetime_disable_on=true&onetime_disable_time=" + start_ts + "&_sid=" + sid;
                break;
            default:
                message = "something happened, try again ! (IMPOSSIBLE)";
        }

        //url_path = "/webapi/entry.cgi?api=SYNO.SurveillanceStation.HomeMode&version=1&method=Switch&on=" + bool + "&_sid=" + sid;
        method = "GET"
        onload_switch_function = function (xhr) {
            response = JSON.parse(xhr.responseText);
            if (response.success == true) {
                switch (bool) {
                    case true:
                        message = "Home mode is ON (camera is off)";
                        break;
                    case false:
                        message = "Home mode is OFF (camera is on)";
                        break;
                    default:
                        message = "something happened, try again ! (IMPOSSIBLE)";
                }
            } else {
                message = "something happened, try again ! (S200)";
            }
            // Build message
            dict = {
                'status': message,
            };

            // Send the message
            Pebble.sendAppMessage(dict, function (e) {
                console.log('sent');
            }, function () {
                console.log('failed');
            });
        }
        max_retry = 10;
        xhr_to_syno(method, url_path, onload_switch_function, max_retry, 10000);


    } else {
        authenticate();
        switch_home(bool);
    }

}

// Get JS readiness events
Pebble.addEventListener('ready', function (e) {
    console.log("---- local storage:");
    console.log("user " + JSON.parse(localStorage.getItem('clay-settings')).username);
    console.log('PebbleKit JS is ready');
    // Update Watch on this
    Pebble.sendAppMessage({ 'JSReady': 1 });
});

// Get AppMessage events
Pebble.addEventListener('appmessage', function (e) {
    // Get the dictionary from the message
    var dict = e.payload;
    console.log(dict[0].toString());
    switch (dict[0]) {
        case 'auth':
            if (!authenticate()){
                console.log("---- waited 1sec:");
                setTimeout(authenticate(),1000);
            }
            break;
        case 'get':
            get_status();
            break;
        case 'home_on':
            switch_home(true);
            break;
        case 'home_off':
            switch_home(false);
            break;
        default:
            console.log('Sorry. I don\'t understand your request :' + dict[0]);
    }

});