/**
 *
 * A Wrapper for magento cache:flush for Redis
 *
 *
 * This will clean magento redis cache keys for relevant cache types.
 */
var REDIS = require('redis'),
    Q = require('q'),
    VM_HOST = 'magedemo.v.ctidigital.com',
    ZEND_CACHE_PREFIX_KEY = 'zc:k:',
    ZEND_CACHE_PREFIX_TAG_IDS = 'zc:ti:',
    REDIS_PORT = 6379,
    queryHelper,
    magentoRedisCache;

// Define the db names and commands
// to build redis queries
queryHelper = {
    'db': {
        // Map of DB's inside Magento Redis Cache
        'cache': 0,
        'fullPageCache': 1,
        'sessionsCache': 2
    },
    'tags': {
        // List of Redis Queries
        'mage': '*_MAGE',
        'fpc': '*_FPC',
        'layout': '*_LAYOUT_GENERAL_CACHE_TAG',
        'block': '*_BLOCK_HTML'
    }
};

/**
 * Magento Redis Cache Main wrapper
 *
 * @type {{_debug: boolean, _redisClient: {}, _redisConfig: {host: string, port: number}, init: init, connect: connect, disconnect: disconnect, addPrefixKey: addPrefixKey, getCacheIDForTag: getCacheIDForTag, deleteKeysWithinTags: deleteKeysWithinTags, flushFullPage: flushFullPage, flushLayout: flushLayout, flushBlock: flushBlock, debug: debug, showError: showError}}
 */
magentoRedisCache = {
    _debug: false,
    _redisClient: {},
    _redisConfig: {
        host: VM_HOST,
        port: REDIS_PORT
    },

    /**
     * Initialise the Redis Wrapper
     *
     * @param config {object} - Redis url and port config
     * @param debug {Boolean} - Show/Hide debug messages
     */
    init: function (config, debug) {
        // Initialise Redis Config
        this._redisConfig = (typeof config !== 'undefined') ? config : this._redisConfig;

        // Set flag for debug logs
        this._debug = (typeof debug !== 'undefined') ? debug : this._debug;

        this.debug('Magento Redis config Initialised');
    },

    /**
     * Connect to Redis host
     */
    connect: function () {
        var _defer = Q.defer(),
            _self = this;

        this.debug('Connect to redis host `' + this._redisConfig.host + '` port ' + this._redisConfig.port);

        // Create redisClient
        this._redisClient = REDIS.createClient(this._redisConfig);

        // Redis Connection Error Event
        this._redisClient.on('error', function (err) {
            // _self.showError(err);
            _defer.reject(err);
        });

        this._redisClient.on('ready', function () {
            _self.debug('Redis connected.');
            _defer.resolve();
        });

        this._redisClient.on('end', function () {
            _self.debug('Redis disconnected.');
        });

        return _defer.promise;
    },

    /**
     * Disconnect from Redis host
     */
    disconnect: function () {
        this.debug('Disconnect redis...');
        this._redisClient.quit();
        this.debug('Disconnected redis');
    },

    /**
     * Prefix cache tags if there is no Cache Key Prefix
     *
     * @param tags {object} - Tags array/object to be prefixed
     * @returns {*} - Prefixed Tags array/object
     */
    addPrefixKey: function (tags) {
        var tag,
            i;

        for (i = 0; i < tags.length; i++) {
            tag = tags[i];
            if (tag.indexOf(ZEND_CACHE_PREFIX_KEY) === -1) {
                tags[i] = (ZEND_CACHE_PREFIX_KEY + tags[i]);
            }
        }
        return tags;
    },

    /**
     * Gets Cache ID's for cache TAGS
     *
     * @param db {object} - Redis DB to query for cache tags
     * @param tag {string} - Redis Tag name
     * @return {promise}
     */
    getCacheIDForTag: function (db, tag) {
        var _defer = Q.defer(),
            _self = this,
            tagFound = ' found for Query `' + tag + '` on db ' + db,
            tagNotFound = 'Tag not found for Query `' + tag + '` on db ' + db;

        this._redisClient
            .multi()
            .select(db)
            .keys(tag).exec(function (err, replies) {
            var keysReply;

            if (err) {
                _self.showError(err);
                _defer.reject(err);
                return;
            }

            if (typeof replies !== 'undefined') {
                if (replies.length > 1) {
                    keysReply = replies[1][0];
                    if (typeof keysReply !== 'undefined') {
                        if (keysReply.length > 1) {
                            if (keysReply.indexOf(ZEND_CACHE_PREFIX_TAG_IDS) !== -1) {
                                _self.debug(keysReply + tagFound);
                                _defer.resolve(keysReply);
                                return;
                            }
                        }
                    }
                }
            }

            _self.showError(tagNotFound);
            _defer.reject(tagNotFound);
        });

        return _defer.promise;
    },

    /**
     * Sinter the tags find keys and delete them
     *
     * @param tags {object} - Tags to run Query
     * @param _db {object} - DB ID to run the Query
     * @return {promise}
     */
    deleteKeysWithinTags: function (tags, _db) {
        var _defer = Q.defer(),
            _self = this;

        //noinspection JSUnresolvedFunction
        _self._redisClient
            .multi()
            .select(_db)
            .sinter(tags, function (err, replies) {
                var keysToDel;
                if (err) {
                    return;
                }

                // 3. Remove Keys
                if (typeof replies !== 'undefined') {
                    if (replies.length > 0) {
                        keysToDel = _self.addPrefixKey(replies);
                        _self.debug('\n Delete Keys from db ' + _db + ':\n  ' + keysToDel + '\n');

                        _self._redisClient.del(
                            keysToDel, function (_err, _replies) {
                                if (err) {
                                    _self.showError(_err);
                                    _defer.reject(_err);
                                    return;
                                }

                                _self.debug('Success, Deleted Keys from db ' + _db + ' :' + _replies);
                                _defer.resolve(_replies);
                            });
                    }
                }
            })
            .exec(function (err) {
                if (err) {
                    _self.showError(err);
                    _defer.reject(err);
                }
            });

        return _defer.promise;
    },

    /**
     * Flush full page cache type from redis
     * @return {promise}
     */
    flushFullPage: function () {
        var _defer = Q.defer(),
            _self = this;

        this.debug('Flush fullpage cache...');

        // Redis Query (Ported from redis.php in magento2)
        // 1. Get the full 'FPC' Tag ID using partial Tag Queries
        /*_self.getCacheIDForTag(
            queryHelper.db.fullPageCache,
            queryHelper.tags.fpc
        ).then(function (fpcTagID) {
            return [
                fpcTagID,
                _self.getCacheIDForTag(
                    queryHelper.db.fullPageCache,
                    queryHelper.tags.mage
                )
            ];
        }).spread(function (fpcTagID, mageTagID) {
            // 2. SINTER Selected 'FPC' Tag with 'MAGE' tag
            var tags = [];
            tags.push(fpcTagID);
            tags.push(mageTagID);

            _self.deleteKeysWithinTags(tags, queryHelper.db.fullPageCache)
                .then(function (replies) {
                    _self.debug('Flushed fullpage cache');
                    _defer.resolve(replies);
                }).fail(function (error) {
                _defer.reject(error);
            });

        });*/
        _defer.resolve();
        return _defer.promise;
    },

    /**
     * Flush layout cache type from redis
     * @return {promise}
     */
    flushLayout: function () {
        var _defer = Q.defer(),
            _self = this;

        this.debug('Flush layout cache...');

        // Redis Query (Ported from redis.php in magento2)
        // 1. Get the full 'LAYOUT' Tag ID using partial Tag Queries
        _self.getCacheIDForTag(
            queryHelper.db.cache,
            queryHelper.tags.layout
        ).then(function (layoutTagID) {
            return [
                layoutTagID,
                _self.getCacheIDForTag(
                    queryHelper.db.cache,
                    queryHelper.tags.mage
                )
            ];
        }).spread(function (layoutTagID, mageTagID) {
            // 2. SINTER Selected 'LAYOUT' Tag with 'MAGE' tag
            var tags = [];
            tags.push(layoutTagID);
            tags.push(mageTagID);

            _self.deleteKeysWithinTags(tags, queryHelper.db.cache)
                .then(function (replies) {
                    _self.debug('Flushed layout cache');
                    _defer.resolve(replies);
                }).fail(function (error) {
                _defer.reject(error);
            });

        });

        return _defer.promise;
    },

    /**
     * Flush block html cache type from redis
     * @return {promise}
     */
    flushBlock: function () {
        var _defer = Q.defer(),
            _self = this;

        this.debug('Flush block cache...');

        // Redis Query (Ported from redis.php in magento2)
        // 1. Get the full 'BLOCK' Tag ID using partial Tag Queries
        _self.getCacheIDForTag(
            queryHelper.db.cache,
            queryHelper.tags.block
        ).then(function (blockTagID) {
            return [
                blockTagID,
                _self.getCacheIDForTag(
                    queryHelper.db.cache,
                    queryHelper.tags.mage
                )
            ];
        }).spread(function (blockTagID, mageTagID) {
            // 2. SINTER Selected 'LAYOUT' Tag with 'MAGE' tag
            var tags = [];
            tags.push(blockTagID);
            tags.push(mageTagID);

            _self.deleteKeysWithinTags(tags, queryHelper.db.cache)
                .then(function (replies) {
                    _self.debug('Flushed block cache');
                    _defer.resolve(replies);
                }).fail(function (error) {
                _defer.reject(error);
            });

        });
        return _defer.promise;
    },

    /**
     * Show Debug messages
     * @param str
     */
    debug: function (str) {
        if (this._debug === false) {
            return;
        }
        console.log('rediscache.js: ' + str);
    },

    /**
     * Show error messages
     * @param err
     */
    showError: function (err) {
        console.error('ERROR (rediscache.js): ', err);
    }
};

module.exports = {
    cache: magentoRedisCache
};



