import express from 'express';
import svgCaptcha from 'svg-captcha';
import Utils from '../../app/Utils.js';

const collection = 'users';

/**
 * UsersController. API for the user management, граничен клас за комуникация с потребителския модул
 */
class UsersController {
    name = 'userApi'
    route = '/api/user'

    init(app) {
        const { db, am, user, global } = app;
        const router = express.Router();

        router.get('/info', (req, res) => {
            res.json({ user: req.user });
        })

        router.post('/signin', function (req, res, next) {
            user.passport.authenticate('local', function (err, user, info) {
                if (err) { return next(err); }
                if (!user) {
                    am.audit(req, 'login:error', null, { message: info.message });
                    return res.json({ status: 'error', message: info.message })
                }
                req.login(user, (err) => {
                    if (err) {
                        am.audit(req, 'login:error', null, { err });
                        return next(err);
                    }
                    res.json({ status: 'OK', user: req.user });
                    am.audit(req, 'login');
                })
            })(req, res, next);
        });

        router.post('/signup', async (req, res) => {
            try {
                await user.signUp(req, req.body);
                res.json({ status: "OK", user: req.user });
            } catch (err) {
                res.json({ status: 'error', message: err.message, user: null });
            }
        });

        router.get('/signout', async (req, res) => {
            am.audit(req, 'logout');
            req.logout(then => {
                res.json({ status: 'OK' });
            });
        })

        router.get('/auth/facebook', user.passport.authenticate('facebook', { scope: ['email'] }));
        router.get('/auth/facebook/callback', am.getSocialCallback('facebook'));

        router.get('/auth/google', user.passport.authenticate('google', { scope: ['profile', 'email'] }));
        router.get('/auth/google/callback', am.getSocialCallback('google'));

        router.post('/tm', async (req, res) => {
            am.audit(req, 'tm:' + req.body.action, req.body.object, req.body.data)
            res.json({ status: "OK" });
        })

        router.post('/update', am.user, async (req, res) => {
            try {
                await user.update(req, req.body);
                res.json({ status: 'OK' });
            } catch (err) {
                res.json({ status: 'error', message: err.message});
            }
        })

        router.post('/forgotten', async (req, res) => {
            try {
                await user.forgotten(req, req.body);
                res.json({ status: "OK" });
            } catch (err) {
                res.json({ status: 'error', message: err.message });
            }
        })

        router.post('/reset', async (req, res) => {
            try {
                await user.reset(req, req.body);
                res.json({ status: "OK" });
            } catch (err) {
                res.json({ status: 'error', message: err.message });
            }
        });

        router.post('/send-validation-email', async (req, res) => {
            let dbUser = await db.get(collection, { '_id': db.ObjectId(req.body._id) });
            if (dbUser.email != req.user?.email) {
                res.json({ status: 'error', message: 'invalidEmail' });
            }
            if (dbUser) {
                if (dbUser.status == 9) {
                    await user.sendValidationEmail(req, dbUser);
                    res.json({ status: "OK" });
                } else if (dbUser.status == 10) {
                    res.json({ status: 'error', message: 'emailAlreadyValidated' });
                }
            } else {
                res.json({ status: 'error', message: 'invalidEmail' });
            }
        })

        router.post('/validate-email', async (req, res) => {
            try {
                await user.validateEmail(req, req.body);
                res.json({ status: "OK" });
            } catch (err) {
                res.json({ status: 'error', message: err.message });
            }
        })

        router.get('/get/:id', am.admin, async (req, res) => {
            let user = await db.get(collection, { '_id': db.ObjectId(req.params.id) }, { password: 0 });
            res.json(user);
        })

        router.delete('/delete/:id', am.admin, async (req, res) => {
            await user.delete(req, req.params.id);
            res.json({ status: 'OK' });
        })

        router.post('/list', am.admin, async (req, res) => {
            let q = {
                query: {},
                project: { password: 0 },
                limit: req.body.limit || 12, skip: req.body.skip || 0
            };
            if (req.body.email) {
                q.query.email = { $regex: Utils.escapeRegExp(req.body.email), $options: 'i' }
            }
            let list = await db.list(collection, q);
            res.json(list);
        })

        router.get('/captcha', (req, res) => {
            let captcha = svgCaptcha.create({
                noise: 2,
                color: true
            });
            req.session.captcha = captcha.text;
            res.type('svg');
            res.status(200).send(captcha.data);
        })

        router.post('/i-am-not-a-robot', async (req, res) => {
            if (req.body.captcha?.toLowerCase() == req.session.captcha?.toLowerCase()) {
                let cache = db.instance.collection('cache');
                let queryKey = {
                    scope: 'ip', key: req.clientIP
                }
                let ipInfo = await cache.findOne(queryKey)
                if (ipInfo) {
                    ipInfo.objects = [];
                    await cache.replaceOne(queryKey, ipInfo);
                }
                res.json({ status: 'OK' });
            } else {
                res.json({ status: 'error', message: 'invalidCaptcha' });
            }
        })

        router.get('/gameData', (req, res) => {
            res.json(req.user?.gameData || req.session.gameData || []);
        })

        router.put('/gameData', async (req, res) => {
            await user.addGameData(req, req.body);
            res.json(req.user?.gameData || req.session.gameData || []);
        })

        app.webServer.xapp.use(this.route, router);
    }
}

export { UsersController }