var _ = require('lodash'),
    models = require('../../models'),
    common = require('../../lib/common'),
    security = require('../../lib/security'),
    strategies;

strategies = {

    /**
     * ClientPasswordStrategy
     *
     * This strategy is used to authenticate registered OAuth clients.  It is
     * employed to protect the `token` endpoint, which consumers use to obtain
     * access tokens.  The OAuth 2.0 specification suggests that clients use the
     * HTTP Basic scheme to authenticate (not implemented yet).
     * Use of the client password strategy is implemented to support ember-simple-auth.
     */
    clientPasswordStrategy: function clientPasswordStrategy(clientId, clientSecret, done) {
        return models.Client.findOne({slug: clientId}, {withRelated: ['trustedDomains']})
            .then(function then(model) {
                if (model) {
                    var client = model.toJSON({withRelated: ['trustedDomains']});
                    if (client.status === 'enabled' && client.secret === clientSecret) {
                        return done(null, client);
                    }
                }
                return done(null, false);
            });
    },

    /**
     * BearerStrategy
     *
     * This strategy is used to authenticate users based on an access token (aka a
     * bearer token).  The user must have previously authorized a client
     * application, which is issued an access token to make requests on behalf of
     * the authorizing user.
     */
    bearerStrategy: function bearerStrategy(accessToken, done) {
        return models.Accesstoken.findOne({token: accessToken})
            .then(function then(model) {
                if (model) {
                    var token = model.toJSON();
                    if (token.expires > Date.now()) {
                        return models.User.findOne({id: token.user_id})
                            .then(function then(model) {
                                if (!model) {
                                    return done(null, false);
                                }

                                if (!model.isActive()) {
                                    throw new common.errors.NoPermissionError({
                                        message: common.i18n.t('errors.models.user.accountSuspended')
                                    });
                                }

                                var user = model.toJSON(),
                                    info = {scope: '*'};

                                return done(null, {id: user.id}, info);
                            })
                            .catch(function (err) {
                                return done(err);
                            });
                    } else {
                        return done(null, false);
                    }
                } else {
                    return done(null, false);
                }
            });
    },

    /**
     * Ghost Strategy
     * ghostAuthRefreshToken: will be null for now, because we don't need it right now
     *
     * CASES:
     * - via invite token
     * - via normal sign in
     * - via setup
     */
    ghostStrategy: function ghostStrategy(req, ghostAuthAccessToken, ghostAuthRefreshToken, profile, done) {
        var inviteToken = req.body.inviteToken,
            options = {context: {internal: true}},
            handleInviteToken, handleSetup, handleSignIn;

        // CASE: socket hangs up for example
        if (!ghostAuthAccessToken || !profile) {
            return done(new common.errors.NoPermissionError({
                help: 'Please try again.'
            }));
        }

        handleInviteToken = function handleInviteToken() {
            var user, invite;
            inviteToken = security.url.decodeBase64(inviteToken);

            return models.Invite.findOne({token: inviteToken}, options)
                .then(function addInviteUser(_invite) {
                    invite = _invite;

                    if (!invite) {
                        throw new common.errors.NotFoundError({
                            message: common.i18n.t('errors.api.invites.inviteNotFound')
                        });
                    }

                    if (invite.get('expires') < Date.now()) {
                        throw new common.errors.NotFoundError({
                            message: common.i18n.t('errors.api.invites.inviteExpired')
                        });
                    }

                    return models.User.add({
                        email: profile.email,
                        name: profile.name,
                        password: security.identifier.uid(50),
                        roles: [invite.toJSON().role_id],
                        ghost_auth_id: profile.id,
                        ghost_auth_access_token: ghostAuthAccessToken
                    }, options);
                })
                .then(function destroyInvite(_user) {
                    user = _user;
                    return invite.destroy(options);
                })
                .then(function () {
                    return user;
                });
        };

        handleSetup = function handleSetup() {
            return models.User.findOne({slug: 'ghost-owner', status: 'inactive'}, options)
                .then(function fetchedOwner(owner) {
                    if (!owner) {
                        throw new common.errors.NotFoundError({
                            message: common.i18n.t('errors.models.user.userNotFound')
                        });
                    }

                    // CASE: slug null forces regenerating the slug (ghost-owner is default and needs to be overridden)
                    return models.User.edit({
                        email: profile.email,
                        name: profile.name,
                        slug: null,
                        status: 'active',
                        ghost_auth_id: profile.id,
                        ghost_auth_access_token: ghostAuthAccessToken
                    }, _.merge({id: owner.id}, options));
                });
        };

        handleSignIn = function handleSignIn() {
            var user;

            return models.User.findOne({ghost_auth_id: profile.id}, options)
                .then(function (_user) {
                    user = _user;

                    if (!user) {
                        throw new common.errors.NotFoundError();
                    }

                    if (!user.isActive()) {
                        throw new common.errors.NoPermissionError({
                            message: common.i18n.t('errors.models.user.accountSuspended')
                        });
                    }

                    return models.User.edit({
                        email: profile.email,
                        name: profile.name,
                        ghost_auth_id: profile.id,
                        ghost_auth_access_token: ghostAuthAccessToken
                    }, _.merge({id: user.id}, options));
                })
                .then(function () {
                    return user;
                });
        };

        if (inviteToken) {
            return handleInviteToken()
                .then(function (user) {
                    done(null, user, profile);
                })
                .catch(function (err) {
                    done(err);
                });
        }

        handleSignIn()
            .then(function (user) {
                done(null, user, profile);
            })
            .catch(function (err) {
                if (!(err instanceof common.errors.NotFoundError)) {
                    return done(err);
                }

                handleSetup()
                    .then(function (user) {
                        done(null, user, profile);
                    })
                    .catch(function (err) {
                        done(err);
                    });
            });
    }
};

module.exports = strategies;
