const fs = require('fs');
const path = require("path");
const mime = require('mime-types');
const fetch = require('node-fetch');
var gCmd = require('node-command-line');
var gAdb = require('adbkit');
var gAdbClient = gAdb.createClient();
var Promise = require('bluebird');
let gTemplate = require("ejs");
const log = require('electron-log');
const moment = require("moment");

//информация об устройствах
var g_devicesInfo = [];
class TDeviceInfo {
    constructor(button_id = -1, device_id = "") {
        this.button_id = button_id;
        this.device_id = device_id;
    }
}

//вспомогательный класс для работы с ответами
class TResponse {
    constructor(response, status_code = 200, rc = 0, data = null) {
        this.status_code = status_code;
        this.rc = rc;
        this.data = data;
        this.response = response;
    }
    static create(response, status_code = 200, rc = 0, data = null) { return new TResponse(response, status_code, rc, data); }
    result() {
        this.response.writeHead(this.status_code);
        this.response.end(JSON.stringify({ rc: this.rc, data: this.data }));
    }
    static prepare(response, status_code = 200, rc = 0, data = null) {
        TResponse.create(response, status_code, rc, data).result();
    }
}

function redirectButtonsModuleUrl(url, params) {
    let result = url;
    let str_pos = url.indexOf("buttons_module");
    if (str_pos >= 0) {
        let new_url = url.substr(str_pos + 14);
        result = path.join(params.content_path, new_url);
    }
    return result;
}

//функция устанавливает APK на кнопку. параметры:
// params.button_id - идентфикатор кнопки
// params.device_id - идентфикатор устройства
// params.content_path - путь до папки с данными по кнопке
module.exports.updateButtonsAPK = function (params) {
    try {
        //определяем путь до apk для данной кнопки
        let button_apk = path.resolve(params.content_path, "button_update/button" + params.button_id + ".apk");
        //если есть такой файл, значит надо обновлять
        if (!fs.existsSync(button_apk)) return false;

        //получаем список устройств, подцепленных к пк
        gAdbClient.listDevices()
            .then(function (devices) {
                return Promise.filter(devices, function (device) {
                    try {
                        if (device.id == params.device_id) {
                            gAdbClient.install(device.id, button_apk, function (error) {
                                try {
                                    if (error != null) {
                                        log.error('Error updateButtonsAPK:', error);
                                        return;
                                    }
                                    //и запускаем его
                                    gAdbClient.shell(device.id, "am start -n com.example.android.myapplicationbrowser/com.example.android.myapplicationbrowser.MainActivity", function (error) {
                                        try {
                                            if (error == null) {
                                                //если нормально установили и запустили apk, то удаляем файл
                                                //fs.unlink(button_apk,function(error) { console.log(error); } );
                                            }
                                        } catch (ex) { log.error('Error updateButtonsAPK:', error); }
                                    });
                                } catch (ex) {
                                    log.error('Error updateButtonsAPK:', error);
                                }
                            });
                        }
                    } catch (ex) {
                        log.error('Error updateButtonsAPK:', ex.message);
                    }
                    return false;
                })
            })
            .catch(function (err) {
                log.error('Error updateButtonsAPK:', err.stack)
            });
    } catch (ex) {
        log.error('Error updateButtonsAPK:', ex.message);
    }
};

//функция запускает приложение на всех устройствах, подключенных к adb
module.exports.startButtonsAPK = function (params) {
    try {
        //получаем список устройств, подцепленных к пк
        gAdbClient.listDevices()
            .then(function (devices) {
                return Promise.filter(devices, function (device) {
                    try {
                        //проходимся по списку устройств и запускаем приложение
                        gAdbClient.shell(device.id, "am start -n com.example.android.myapplicationbrowser/com.example.android.myapplicationbrowser.MainActivity", function (error) {
                            if (error != null) log.error('Error startButtonsAPK:', error.stack);
                        });
                    } catch (ex) {
                        log.error('Error startButtonsAPK:', ex.message);
                    }
                })
            })
            .catch(function (err) {
                log.error('Error startButtonsAPK:', err.stack);
            });
    } catch (ex) {
        log.error('Error startButtonsAPK:', ex.message);
    }
};

//функция перазапускает телефоны
module.exports.rebootButtons = function (params) {
    try {
        //получаем список устройств, подцепленных к пк
        gAdbClient.listDevices()
            .then(function (devices) {
                return Promise.filter(devices, function (device) {
                    //проходимся по списку устройств и запускаем приложение
                    gAdbClient.shell(device.id, "reboot", function (error) {
                        if (error != null) { }
                    });
                })
            })
            .catch(function (err) {
                log.error('Error rebootButtons:', err.stack);
            });
    } catch (ex) {
        log.error('Error rebootButtons:', ex.stack);
    }

};

module.exports.updateButtonsAPKs = function (params) {
    try {
        g_devicesInfo.forEach(function (deviceInfo) {
            module.exports.updateButtonsAPK({
                content_path: params.content_path,
                device_id: deviceInfo.device_id,
                button_id: deviceInfo.button_id
            });
        });
    } catch (ex) {
        log.error('Error updateButtonsAPKs:', ex.stack);
    }

};

//функция перазапускает телефоны
module.exports.rebootButtons = function (params) {
    try {
        //получаем список устройств, подцепленных к пк
        gAdbClient.listDevices()
            .then(function (devices) {
                return Promise.filter(devices, function (device) {
                    try {
                        //проходимся по списку устройств и запускаем приложение
                        gAdbClient.shell(device.id, "reboot", function (error) {
                            if (error != null) {
                                log.error('Error rebootButtons:', error);
                            }
                        });
                    } catch (ex) {
                        log.error('Error rebootButtons:', ex.message);
                    }
                })
            })
            .catch(function (err) {
                log.error('Error rebootButtons:', err.stack);
            });
    } catch (ex) {
        log.error('Error rebootButtons:', ex.message);
    }
};

//функция запускает приложение на всех устройствах, подключенных к adb
module.exports.startADB = function () {
    try {
        gCmd.run("adb_run", function (error) { if (error != null) { log.error("Error! startADB: " + error); } });
    } catch (ex) {
        log.error("Error! startADB: " + ex.message);
    }
};

//функция извлекает из request параметры query string
module.exports.queryParams = function (request) {
    let q = request.url.split('?'), result = {};
    if (q.length >= 2) {
        q[1].split('&').forEach((item) => {
            try {
                result[item.split('=')[0]] = item.split('=')[1];
            } catch (e) {
                result[item.split('=')[0]] = '';
            }
        })
    }
    return result;
};

//функция обрабаытвает входящий запрос. если этот запрос касается кнопок, то возвращается true
module.exports.processRequest = function (request, response, params) {
    try {
        //проверяем, начинается ли запрос с "/button_api"
        //если да, значит этот запрос касается кнопок
        let button_pattern = /^(\/buttons_api)/;
        if (button_pattern.test(request.url)) {
            //извлекаем параметры запроса (из query string)
            let query_params = this.queryParams(request);

            //по action определяем тип запроса
            switch (query_params.action) {
                case "get": {   //запрос на получение данных для кнопки
                    if (typeof params.isBlockPlayButtons === 'undefined' || params.isBlockPlayButtons) {
                        TResponse.prepare(response, 500);
                        return true;
                    }

                    if (typeof query_params.button_id === 'undefined') {
                        TResponse.prepare(response, 200, 200, { error: "Undefined button_id" });
                        return true;
                    }

                    if (typeof query_params.device_id === 'undefined') {
                        TResponse.prepare(response, 200, 200, { error: "Undefined device_id" });
                        return true;
                    }

                    let currentDeviceInfo = null;
                    g_devicesInfo.forEach(function (deviceInfo) {
                        if (deviceInfo.button_id == query_params.button_id) {
                            currentDeviceInfo = deviceInfo;
                            return false;
                        }
                    });
                    if (currentDeviceInfo == null) {
                        currentDeviceInfo = new TDeviceInfo(query_params.button_id, query_params.device_id);
                        g_devicesInfo.push(currentDeviceInfo);
                    }
                    currentDeviceInfo.button_id = query_params.button_id;
                    currentDeviceInfo.device_id = query_params.device_id;

                    query_params.content_path = params.content_path;

                    this.echoButtonContent(query_params, response);
                    return true;
                }
                case "click": {  //запрос при клике на кнопке
                    TResponse.prepare(response, 200, 0);

                    //здесь можно обрабатывать нажатие на кнопку
                    if (typeof params !== 'undefined' && typeof params.onclick === 'function') {
                        params.onclick(query_params);
                    }

                    return true;
                }
                case "send_sms": {  //запрос на отправку смс
                    //проверка входящих параметров
                    if (typeof query_params.event_id === 'undefined') {
                        TResponse.prepare(response, 200, 200, { error: "Undefined event_id" });
                        return true;
                    }
                    if (typeof query_params.phone === 'undefined') {
                        TResponse.prepare(response, 200, 200, { error: "Undefined phone" });
                        return true;
                    }
                    let phone_pattern = /^(\+)?[\d]{11,14}$/;
                    if (!phone_pattern.test(query_params.phone)) {
                        TResponse.prepare(response, 200, 201, { error: "Incorrect phone number" });
                        return true;
                    }

                    let event_config;
                    let event_config_filename = path.join(params.content_path, "button_events/event_" + query_params.event_id + "/config.json");
                    try {
                        if (fs.existsSync(event_config_filename)) {
                            event_config = JSON.parse(fs.readFileSync(event_config_filename, "utf-8"));
                        } else {
                            TResponse.prepare(response, 200, 202, { error: "Unavailable event_id" });
                            return true;
                        }
                    } catch (err) {
                        TResponse.prepare(response, 200, 202, { error: "Unavailable event_id" });
                        return true;
                    }

                    let request_options = {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                        body: "phone=" + encodeURIComponent(query_params.phone) + "&message=" + event_config.send_sms_text
                    };

                    //fetch('http://akzia-navigazia-admin/ak-bd-admin/api/services/send_sms',request_options)
                    fetch('http://esk.akzia.com/ak-admin.ru/ak-bd-admin/api/services/send_sms', request_options)
                        .then(function (res) {
                            return res.json();
                        })
                        .then(function (res_json) {
                            if (res_json.rc == 5001) { res_json.rc = 0; res_json.data = null; }
                            TResponse.prepare(response, 200, res_json.rc);
                        })
                        .catch(function (error) {
                            TResponse.prepare(response, 200, 1001);
                        });

                    return true;
                }
                case "update": {   //запрос на обновление apk
                    //проверяем параметры запроса
                    if (typeof query_params.button_id === 'undefined') {
                        TResponse.prepare(response, 200, -2, { error: "Undefined button_id" });
                        return true;
                    }

                    if (typeof query_params.device_id === 'undefined') {
                        TResponse.prepare(response, 200, -3, { error: "Undefined device_id" });
                        return true;
                    }

                    this.updateButtonsAPK({
                        content_path: params.content_path,
                        button_id: query_params.button_id,
                        device_id: query_params.device_id
                    });

                    TResponse.prepare(response, 200);

                    return true;
                }
                case "get_update_time": {   //запрос на время обновление apk
                    TResponse.prepare(response, 200, 0, ((typeof params.lastUpdate === 'undefined' || params.lastUpdate == false) ? "0" : (moment(params.lastUpdate, 'YYYYMMDDHHmmss').unix() + 1)));
                    return true;
                }
                default: {
                    //console.log('Unknown action: ' + query_params.action);
                    TResponse.prepare(response, 200, -1, { error: "Unknown action" });
                    return true;
                }
            }
            return true;
        }

        //проверяем, начинается ли запрос с "/data/"
        //если да, значит этот запрос получение файлов
        let data_pattern = /^(\/buttons_module\/)/;
        if (data_pattern.test(request.url)) {
            let filePath = redirectButtonsModuleUrl(request.url, params);
            if (fs.existsSync(filePath)) {
                let stat = fs.statSync(filePath);
                response.writeHead(200, {
                    'Content-Type': mime.lookup(filePath),
                    'Content-Length': stat.size
                });
                let readStream = fs.createReadStream(filePath);
                // We replaced all the event handlers with a simple call to readStream.pipe()
                try { readStream.pipe(response); } catch (e) {
                    console.error(e);
                }
            } else {
                log.error('ButtonsAPI: No such file: ' + filePath);
                response.writeHead(500);
                response.end();
            }
            return true;
        }
    } catch (ex) {
        log.error("Error on request: " + request.url + "(" + ex.message + ")");
        response.writeHead(500);
        response.end();

        return true;
    }

    return false;
};

module.exports.echoButtonContent = function (params, response) {
    let button_url = "/buttons_module/button_contents/button_" + params.button_id;
    let str = redirectButtonsModuleUrl(button_url + "/index.html", params);
    gTemplate.renderFile(str, { button_url: button_url }, function (err, data) {
        if (!err) {
            //response.setHeader("Content-Length", data.length);
            response.statusCode = 200;
            response.write(data);
            response.end();
        } else {
            response.writeHead(500);
            response.end();
        }
    });
};

module.exports.isNeedUpdateContent = function () {
    return new Promise(function (resolve, reject) {
        try { resolve(); }
        catch (ex) { log.error("Error! isNeedUpdateContent: " + ex.message); }
    });
};