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() {
    send_message_to_watch("Authenticating..")
    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)) < 12) {
        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) { // IP blocked by syno (or by syno Firewall)
                    console.log('------xhr status 407 IP blocked by syno (or by syno Firewall) ');
                    onload_function(xhr);
                    return false;
                } else if (xhr.status == 400) { //wrong credentials
                    console.log('------xhr status wrong user or password ');
                    onload_function(xhr);
                    return false;
                } else if (xhr.status == 404) { //wrong OTP
                    console.log('------xhr status 404 wrong OTP ');
                    onload_function(xhr);
                    return false;
                } else if (xhr.status == 0) { //timeout
                    console.log('------xhr timed out');
                    //send back "timeout" to watch
                    //message = "Time out";
                    //send_message_to_watch(message)
                    onload_function(xhr);
                } else { // why would this happen?
                    console.log('------xhr request returned error code ' + xhr.status);
                    message = "Error (XHR" + xhr.status + ")";
                    send_message_to_watch(message)
                    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(action_callback) {    
    send_message_to_watch("Authenticating.")
    var response;
    sid = ""; //re-use sid from another session (7 days before expiry)
    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;
        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) {
                setTimeout( function () {
                    send_message_to_watch("Authenticating...");
                    home_mode_handler(action_callback);
                    }
                    ,4000);
                return false
            }
            console.log('-- otp_code is :' + otp_code)
            url_path = url_path + "&otp_code=" + otp_code
        }
        var method = "GET";
        onload_function = function (xhr) {
            console.log(JSON.stringify(xhr));
            if (xhr.status == 0){
                console.log('------Authentication failed because of request timed out');
                message = "Time out";
                send_message_to_watch(message)
            } else {
                response = JSON.parse(xhr.responseText);
                if (response.success == true) {
                    sid = response.data.sid;
                    console.log('------Authentication succeeded');
                    if (sid != "") {
                        message = "Authenticated";
                        send_message_to_watch(message)
                        home_mode_handler(action_callback);
                    } else {
                        console.log('------Unexpected error : authentication is OK but no SID retrieved');
                        message = "Auth error, no SID";
                        send_message_to_watch(message)
                    }
                } 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";
                    } else if (response.error.code == 407) {
                        console.log('------Authentication failed because of IP Blocked');
                        message = "Authentication failed, IP is blocked";
                    }
                    send_message_to_watch(message)
                }
            }
        };        
        send_message_to_watch("Authenticating....");
        max_retry = 0;
        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)";
            }
            send_message_to_watch(message)
        }

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

    } else {
        authenticate("get");
    }

}

function home_mode_handler(action) {
    var response;
    var duration = 15 * 60
    if (sid != "") {
        console.log('---- switching home mode to ' + action);
        var epoch = Math.round(new Date().getTime() / 1000.0);
        var start_ts = epoch + 10;
        method = "GET";
        max_retry = 0;
        
        switch (action) {
            case "home_on":
                send_message_to_watch("Setting Home Mode to ON")
                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 "home_off":
                send_message_to_watch("Setting Home Mode to OFF")
                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;
            case "timed":
                send_message_to_watch("Temporary setting Home Mode to ON")
                var end_ts = duration + start_ts
                var d = new Date(end_ts * 1000)
                var end_time = d.toLocaleTimeString("fr-FR",{timestyle:'short'});
                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;    
                break;
            default:
                message = "something happened, try again ! (IMPOSSIBLE)";
        }
        
        onload_switch_function = function (xhr) {
            response = JSON.parse(xhr.responseText);
            console.log(response.success);
            if (response.success == true) {
                switch (action) {
                    case "home_on":
                        message = "Home mode is ON (camera is off)";
                        break;
                    case "home_off":
                        message = "Home mode is OFF (camera is on)";
                        break;
                    case "timed":
                        message = "Home mode is ON until " + end_time;
                        break;
                    default:
                        message = "something happened, try again ! (IMPOSSIBLE)";
                }
            } else {
                message = "something happened, try again ! (S200)";
            }
            send_message_to_watch(message)
        }
        max_retry = 0;
        xhr_to_syno(method, url_path, onload_switch_function, max_retry, 10000);


    } else {
        authenticate(action);
    }

}

function send_message_to_watch(message){
    // Build message
    var dict = {
        'status': message,
    };
    console.log('DSCam Home-Switch: -- message to sent to watch:'+JSON.stringify(dict));
    // Send the message
    Pebble.sendAppMessage(dict, function (e) {
        console.log('DSCam Home-Switch: -- message sent to watch');
    }, function () {
        console.log('DSCam Home-Switch: -- Failed to message sent to watch');
    });
}
// 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 });
    send_message_to_watch("Welcome !")
});

// Get AppMessage events
Pebble.addEventListener('appmessage', function (e) {
    // Get the dictionary from the message
    var dict = e.payload;
    switch (dict[0]) {
        case 'get':
            get_status();
            break;
        case 'timed':
            home_mode_handler("timed"); 
            break;
        case 'home_on':
            home_mode_handler("home_on");
            break;
        case 'home_off':
            home_mode_handler("home_off");
            break;
        default:
            console.log('Sorry. I don\'t understand your request :' + dict[0]);
    }

});