import crypto from 'crypto';
import passport from 'passport';
import session from 'express-session';
import createSQLiteSessionStore from 'connect-sqlite3';
import { Strategy as LocalStrategy } from 'passport-local';
import ChatServer from './index';

export function configurePassport(context: ChatServer) {
    const SQLiteStore = createSQLiteSessionStore(session);
    const sessionStore = new SQLiteStore({ db: 'sessions.db' });

    passport.use(new LocalStrategy(async (email: string, password: string, cb: any) => {
        const user = await context.database.getUser(email);

        if (!user) {
            return cb(null, false, { message: 'Incorrect username or password.' });
        }

        crypto.pbkdf2(password, user.salt, 310000, 32, 'sha256', (err, hashedPassword) => {
            if (err) {
                return cb(err);
            }

            if (!crypto.timingSafeEqual(user.passwordHash, hashedPassword)) {
                return cb(null, false, { message: 'Incorrect username or password.' });
            }

            return cb(null, user);
        });
    }));

    passport.serializeUser((user: any, cb: any) => {
        process.nextTick(() => {
            cb(null, { id: user.id, username: user.username });
        });
    });

    passport.deserializeUser((user: any, cb: any) => {
        process.nextTick(() => {
            return cb(null, user);
        });
    });

    context.app.use(session({
        secret: process.env.AUTH_SECRET || 'keyboard cat',
        resave: false,
        saveUninitialized: false,
        store: sessionStore as any,
    }));
    context.app.use(passport.authenticate('session'));

    context.app.post('/chatapi/login', passport.authenticate('local', {
        successRedirect: '/',
        failureRedirect: '/?error=login'
    }));

    context.app.post('/chatapi/register', async (req, res, next) => {
        const { username, password } = req.body;
        const salt = crypto.randomBytes(32);
        crypto.pbkdf2(password, salt, 310000, 32, 'sha256', async (err, hashedPassword) => {
            if (err) {
                return next(err);
            }
            try {
                await context.database.createUser(username, hashedPassword, salt);

                passport.authenticate('local')(req, res, () => {
                    res.redirect('/');
                });
            } catch (err) {
                res.redirect('/?error=register');
            }
        });
    });

    context.app.all('/chatapi/logout', (req, res, next) => {
        req.logout((err) => {
            if (err) {
                return next(err);
            }
            res.redirect('/');
        });
    });
}