'use strict';

const session = require('express-session');
const __ = require('paradox-utils');
const _ = require('lodash');
const util = require('util');
const logger = require('paradox-logger')('session-datastore');

/**
 * @see https://github.com/expressjs/session#session-store-implementation
 */
class SessionDataStore extends session.Store {

    constructor(options) {
        super(options);

        this.options = _.defaults(options, {
            model: null,
            fetchCache: 5 * 1000,
        });

        this.sessions = {};
    }

    findSessionById(id) {
        if(id in this.sessions) {
            let sess = this.sessions[id];

            // expired
            if(Date.now() - sess.date < this.options.fetchCache) {
                return sess.promise;

            } else {
                delete this.sessions[id];
            }
        }

        this.sessions[id] = {
            date: Date.now(),
            promise: null,
        };

        return this.sessions[id].promise = this
            .options.model
            .then(Model => {
                return Model
                    .findOne({
                        where: {
                            key: id,
                        }
                    });
            });
    }

    /**
     * Fetch session by the given session ID.
     * @param id
     * @param done
     */
    get(id, done) {
        // logger.silly('get session: ' + id);

        this
            .findSessionById(id)
            .then(
                session => {
                    if(!session) {
                        done(null, null);

                    } else {
                        done(null, session.session);
                    }
                },
                err => {
                    done(err);
                }
            );
    }

    /**
     * Commit the given session associated with the given sessionId to the store.
     * @param id
     * @param session
     * @param done
     */
    set(id, session, done) {
        // logger.silly('set session: ' + id, session);

        // console.info(util.inspect(session, null, 10, true));

        this.options.model
            .then(Model => {
                session = JSON.parse(JSON.stringify(session));

                return Model
                    .create({
                        key: id,
                        session: session,
                        username: __.object.queryGet(session, 'passport.user') || null,
                        remote_addr: null,
                        useragent: null,
                    });
            })
            .then(
                instance => {
                    delete this.sessions[id];
                    done();
                },
                err => done(err)
            )
    }

    // /**
    //  * Clear all sessions.
    //  * @param done
    //  */
    // clear(done) {
    //     // console.info("CLEAR");
    //
    //     this.sessions = {};
    //
    //     done();
    // }

    /**
     * Destroy the session associated with the given session ID.
     * @param id
     * @param done
     */
    destroy(id, done) {
        // logger.silly('destroy session: ' + id, session);

        delete this.sessions[id];

        this.options.model
            .then(Model => {
                return Model
                    .destroy({
                        where: {
                            key: id,
                        }
                    })
                    .then(
                        res => done(),
                        err => done(err)
                    );
            });
    }

    // /**
    //  * Touch the given session object associated with the given session ID.
    //  * @param id
    //  * @param session
    //  * @param done
    //  * @returns {*}
    //  */
    // touch(id, session, done) {
    //     // console.info("TOUICH", id);
    //
    //     if(!this.options.model) {
    //         return super.touch(id, session, done);
    //     }
    //
    //     // TODO: Actualizar la petición
    //     done();
    // }
}

module.exports = SessionDataStore;