'use strict';

const router = require('../router.js');
const api = require('../api.js');
const uri = require('../util/uri.js');
const misc = require('../util/misc.js');
const views = require('../util/views.js');
const User = require('../models/user.js');
const UserToken = require('../models/user_token.js');
const topNavigation = require('../models/top_navigation.js');
const UserView = require('../views/user_view.js');
const EmptyView = require('../views/empty_view.js');

class UserController {
    constructor(ctx, section) {
        const userName = ctx.parameters.name;
        if (!api.hasPrivilege('users:view') &&
                !api.isLoggedIn({name: userName})) {
            this._view = new EmptyView();
            this._view.showError('You don\'t have privileges to view users.');
            return;
        }

        this._successMessages = [];
        this._errorMessages = [];

        let userTokenPromise = Promise.resolve([]);
        if (section === 'list-tokens') {
            userTokenPromise = UserToken.get(userName)
                .then(userTokens => {
                    return userTokens.map(token => {
                        token.isCurrentAuthToken = api.isCurrentAuthToken(token);
                        return token;
                    });
                }, error => {
                    return [];
                });
        }

        topNavigation.setTitle('User ' + userName);
        Promise.all([
            userTokenPromise,
            User.get(userName)
        ]).then(responses => {
            const [userTokens, user]  = responses;
            const isLoggedIn = api.isLoggedIn(user);
            const infix = isLoggedIn ? 'self' : 'any';

            this._name = userName;
            user.addEventListener('change', e => this._evtSaved(e, section));

            const myRankIndex = api.user ?
                api.allRanks.indexOf(api.user.rank) :
                0;
            let ranks = {};
            for (let [rankIdx, rankIdentifier] of api.allRanks.entries()) {
                if (rankIdentifier === 'anonymous') {
                    continue;
                }
                if (rankIdx > myRankIndex) {
                    continue;
                }
                ranks[rankIdentifier] = api.rankNames.get(rankIdentifier);
            }

            if (isLoggedIn) {
                topNavigation.activate('account');
            } else {
                topNavigation.activate('users');
            }

            this._view = new UserView({
                user: user,
                section: section,
                isLoggedIn: isLoggedIn,
                canEditName: api.hasPrivilege(`users:edit:${infix}:name`),
                canEditPassword: api.hasPrivilege(`users:edit:${infix}:pass`),
                canEditEmail: api.hasPrivilege(`users:edit:${infix}:email`),
                canEditRank: api.hasPrivilege(`users:edit:${infix}:rank`),
                canEditAvatar: api.hasPrivilege(`users:edit:${infix}:avatar`),
                canEditAnything: api.hasPrivilege(`users:edit:${infix}`),
                canListTokens: api.hasPrivilege(`userTokens:list:${infix}`),
                canCreateToken: api.hasPrivilege(`userTokens:create:${infix}`),
                canEditToken: api.hasPrivilege(`userTokens:edit:${infix}`),
                canDeleteToken: api.hasPrivilege(`userTokens:delete:${infix}`),
                canDelete: api.hasPrivilege(`users:delete:${infix}`),
                ranks: ranks,
                tokens: userTokens,
            });
            this._view.addEventListener('change', e => this._evtChange(e));
            this._view.addEventListener('submit', e => this._evtUpdate(e));
            this._view.addEventListener('delete', e => this._evtDelete(e));
            this._view.addEventListener('create-token', e => this._evtCreateToken(e));
            this._view.addEventListener('delete-token', e => this._evtDeleteToken(e));
            this._view.addEventListener('update-token', e => this._evtUpdateToken(e));

            for (let message of this._successMessages) {
                this.showSuccess(message);
            }

            for (let message of this._errorMessages) {
                this.showError(message);
            }

        }, error => {
            this._view = new EmptyView();
            this._view.showError(error.message);
        });
    }

    showSuccess(message) {
        if (typeof this._view === 'undefined') {
            this._successMessages.push(message)
        } else {
            this._view.showSuccess(message);
        }
    }

    showError(message) {
        if (typeof this._view === 'undefined') {
            this._errorMessages.push(message)
        } else {
            this._view.showError(message);
        }
    }

    _evtChange(e) {
        misc.enableExitConfirmation();
    }

    _evtSaved(e, section) {
        misc.disableExitConfirmation();
        if (this._name !== e.detail.user.name) {
            router.replace(
                uri.formatClientLink('user', e.detail.user.name, section),
                null, false);
        }
    }

    _evtUpdate(e) {
        this._view.clearMessages();
        this._view.disableForm();
        const isLoggedIn = api.isLoggedIn(e.detail.user);
        const infix = isLoggedIn ? 'self' : 'any';

        if (e.detail.name !== undefined) {
            e.detail.user.name = e.detail.name;
        }
        if (e.detail.email !== undefined) {
            e.detail.user.email = e.detail.email;
        }
        if (e.detail.rank !== undefined) {
            e.detail.user.rank = e.detail.rank;
        }

        if (e.detail.password !== undefined) {
            e.detail.user.password = e.detail.password;
        }

        if (e.detail.avatarStyle !== undefined) {
            e.detail.user.avatarStyle = e.detail.avatarStyle;
            if (e.detail.avatarContent) {
                e.detail.user.avatarContent = e.detail.avatarContent;
            }
        }

        e.detail.user.save().then(() => {
            return isLoggedIn ?
                api.login(
                    e.detail.name || api.userName,
                    e.detail.password || api.userPassword,
                    false) :
                Promise.resolve();
        }).then(() => {
            this._view.showSuccess('Settings updated.');
            this._view.enableForm();
        }, error => {
            this._view.showError(error.message);
            this._view.enableForm();
        });
    }

    _evtDelete(e) {
        this._view.clearMessages();
        this._view.disableForm();
        const isLoggedIn = api.isLoggedIn(e.detail.user);
        e.detail.user.delete()
            .then(() => {
                if (isLoggedIn) {
                    api.forget();
                    api.logout();
                }
                if (api.hasPrivilege('users:list')) {
                    const ctx = router.show(uri.formatClientLink('users'));
                    ctx.controller.showSuccess('Account deleted.');
                } else {
                    const ctx = router.show(uri.formatClientLink());
                    ctx.controller.showSuccess('Account deleted.');
                }
            }, error => {
                this._view.showError(error.message);
                this._view.enableForm();
            });
    }

    _evtCreateToken(e) {
        this._view.clearMessages();
        this._view.disableForm();
        UserToken.create(e.detail.user.name, e.detail.note, e.detail.expirationTime)
            .then(response => {
                const ctx = router.show(uri.formatClientLink('user', e.detail.user.name, 'list-tokens'));
                ctx.controller.showSuccess('Token ' + response.token + ' created.');
            }, error => {
                this._view.showError(error.message);
                this._view.enableForm();
            });
    }

    _evtDeleteToken(e) {
        this._view.clearMessages();
        this._view.disableForm();
        if (api.isCurrentAuthToken(e.detail.userToken)) {
            router.show(uri.formatClientLink('logout'));
        } else {
            e.detail.userToken.delete(e.detail.user.name)
                .then(() => {
                    const ctx = router.show(uri.formatClientLink('user', e.detail.user.name, 'list-tokens'));
                    ctx.controller.showSuccess('Token ' + e.detail.userToken.token + ' deleted.');
                }, error => {
                    this._view.showError(error.message);
                    this._view.enableForm();
                });
        }
    }

    _evtUpdateToken(e) {
        this._view.clearMessages();
        this._view.disableForm();

        if (e.detail.note !== undefined) {
            e.detail.userToken.note = e.detail.note;
        }

        e.detail.userToken.save(e.detail.user.name).then(response => {
            const ctx = router.show(uri.formatClientLink('user', e.detail.user.name, 'list-tokens'));
            ctx.controller.showSuccess('Token ' + response.token + ' updated.');
        }, error => {
            this._view.showError(error.message);
            this._view.enableForm();
        });
    }
}

module.exports = router => {
    router.enter(['user', ':name'], (ctx, next) => {
        ctx.controller = new UserController(ctx, 'summary');
    });
    router.enter(['user', ':name', 'edit'], (ctx, next) => {
        ctx.controller = new UserController(ctx, 'edit');
    });
    router.enter(['user', ':name', 'list-tokens'], (ctx, next) => {
        ctx.controller = new UserController(ctx, 'list-tokens');
    });
    router.enter(['user', ':name', 'delete'], (ctx, next) => {
        ctx.controller = new UserController(ctx, 'delete');
    });
};
