/*
 * ADOBE CONFIDENTIAL
 *
 * Copyright (c) 2015 Adobe Systems Incorporated. All rights reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 */

"use strict";

var EventEmitter  = require("events").EventEmitter,
    https         = require("https"),
    Q             = require("q"),
    later         = require("later"),
    _             = require("lodash"),
    logger        = require("../logger");

var PreviewServiceConfiguration = require("./PreviewServiceConfiguration");

var events = new EventEmitter();

var retryInterval = 1;
var retryCount = 0;
var MAX_RETRY_COUNT = 4;
var RETRY_INTERVAL_CAP = 30;

var jsonMimeType = "application/json",
    apiMimeType = "application/vnd.adobe.previewpairing-operation+json";

var _generator,
    connectRetryWrapper,
    accountGuid,
    initialized = false;

var previewServiceApi = {
    accessToken: undefined,

    isHttpOK: function (code) {
        return (Math.floor(code / 200) === 1);
    },

    createRequestCommon: function (options, body) {
        return _.extend(options, {
            hostname: PreviewServiceConfiguration.apiHost,
            port: "443",
            headers: {
                "Content-Type": jsonMimeType,
                "Accept": apiMimeType,
                "Authorization": "Bearer " + previewServiceApi.accessToken,
                "Content-Length": body ? body.length : 0
            }
        });
    },

    createFetchRequest: function () {
        return previewServiceApi.createRequestCommon({
            path: PreviewServiceConfiguration.apiFetchPath,
            method: "GET"
        });
    },

    callRemoteFunction: function (createRequest, body) {
        var result = Q.defer(),
            options = createRequest();

        var req = https.request(options, function(res) {
            res.setEncoding("utf8");

            if (previewServiceApi.isHttpOK(res.statusCode)) {
                var data = "";
                res.on("data", function (chunk) {
                    data += chunk;
                });
                res.on("end", function() {
                    result.resolve(JSON.parse(data));
                });
            } else {
                logger.logMessage(res.statusCode.toString(), logger.LOGLEVEL_ERROR);
                result.reject(res.statusCode);
            }
        });

        req.on("error", function (e) {
            logger.logMessage(e.toString(), logger.LOGLEVEL_ERROR);
            result.reject(e);
        });

        if (body) {
            req.write(body);
        }

        req.end();

        return result.promise;
    },

    fetchConnectedClients: function() {
        var deferred = Q.defer();

        previewServiceApi.callRemoteFunction(previewServiceApi.createFetchRequest).then(
            function(result) {
                deferred.resolve(result);
            },
            function(err) {
                logger.logMessage("unable to fetchConnectedClients: " + err.toString(), logger.LOGLEVEL_ERROR);
                deferred.reject(err);
            }
        );

        return deferred.promise;
    }
};


function fetchConnectedClients() {
    var result = Q.defer();
    logger.logMessage("fetchingConnectedClients");
    previewServiceApi.fetchConnectedClients().then(
        function(clientList) {
            logger.logMessage("Received client list" + clientList);
            events.emit("clientList", clientList);
            result.resolve();
        },
        function () {
            result.reject();
        }
    );
    return result.promise;
}

function clearRetryWrapper() {
    if (connectRetryWrapper) {
        connectRetryWrapper.clear();
        connectRetryWrapper = undefined;
        retryInterval = 1;
        retryCount = 0;
    }
}

function tryConnect() {
    if (previewServiceApi.accessToken) {
        fetchConnectedClients().then(
            function () {
                clearRetryWrapper();
            },
            function () {

                retryInterval = retryCount <= MAX_RETRY_COUNT ? Math.pow(2, retryCount) : RETRY_INTERVAL_CAP;
                retryCount++;

                logger.logMessage("Could not reach API gateway...trying again in " + retryInterval + " minute");

                if (!connectRetryWrapper) {
                    connectRetryWrapper = later.setInterval(
                        function () {
                            tryConnect();
                        }, later.parse.text("every " + retryInterval + " mins")
                    );
                }
            }
        );
    }
}

function queryForClientList() {
    if (connectRetryWrapper) {
        logger.logMessage("Trying to connect when we're in a connect retry loop");
        return;
    }
    
    tryConnect();
}

function init(generator, userId, accessToken) {
    _generator = generator;
    previewServiceApi.accessToken = accessToken;
    accountGuid = userId;

    if (accountGuid) {
        logger.logMessage("PreviewService- Sign In");
        queryForClientList();
    } else {
        logger.logMessage("PreviewService- Sign Out");
        clearRetryWrapper();
        events.emit("shutdown");
    }
    
    if (!initialized) {
        initialized = true;
        
        if (_generator !== undefined) {
            // explicitly query for an updated client list when the document changes
            _generator.onPhotoshopEvent("currentDocumentChanged", queryForClientList);
        }
    }
}

exports.events = events;
exports.queryForClientList = queryForClientList;
exports.init = init;
