import { Router } from 'express';
import SQL from 'sql-template-strings';
import md5 from "js-md5";
import {ulid} from "ulid";
import avatar from "../avatar";
import {handleErrorAsync} from "../../src/helpers";
import { caches }  from "../../src/cache";

const normalise = s => s.trim().toLowerCase();

const calcAge = birthday => {
    if (!birthday) {
        return null;
    }

    const now = new Date();
    const birth = new Date(
        parseInt(birthday.substring(0, 4)),
        parseInt(birthday.substring(5, 7)) - 1,
        parseInt(birthday.substring(8, 10))
    );

    const diff = now.getTime() - birth.getTime();

    return parseInt(Math.floor(diff / 1000 / 60 / 60 / 24 / 365.25));
}

const fetchProfiles = async (db, username, self, isAdmin) => {
    const profiles = await db.all(SQL`
        SELECT profiles.* FROM profiles LEFT JOIN users on users.id == profiles.userId 
        WHERE usernameNorm = ${normalise(username)}
        ORDER BY profiles.locale
    `);

    const p = {}
    for (let profile of profiles) {
        p[profile.locale] = {
            names: JSON.parse(profile.names),
            pronouns: JSON.parse(profile.pronouns),
            description: profile.description,
            age: calcAge(profile.birthday),
            links: JSON.parse(profile.links),
            flags: JSON.parse(profile.flags),
            customFlags: JSON.parse(profile.customFlags),
            words: JSON.parse(profile.words),
            birthday: self ? profile.birthday : undefined,
            teamName: profile.teamName,
            footerName: profile.footerName,
            footerAreas: profile.footerAreas ? profile.footerAreas.split(',') : [],
            card: profile.card,
        };
    }
    return p;
};

function* isSuspicious(profile) {
    const description = profile.description.toLowerCase();
    const flags = JSON.stringify(profile.customFlags).toLowerCase();
    const pronouns = JSON.stringify(profile.pronouns).toLowerCase();

    if (description.includes('superstr') || description.includes('superhet') || description.includes('super-') ||
        flags.includes('superstr') || flags.includes('superhet') || flags.includes('super-')
    ) {
        yield 'Superstraight';
    }

    if (description.includes('phobe') || description.includes('phobic') ||
        flags.includes('phobe') || flags.includes('phobic')
    ) {
        yield '-phobic';
    }

    if (description.includes('terf') || description.includes('radfem') || description.includes('gender critical') ||
        flags.includes('terf') || flags.includes('radfem') || flags.includes('gender critical')
    ) {
        yield 'TERF';
    }

    if (description.includes('helicopter') ||
        flags.includes('helicopter') ||
        pronouns.includes('helicopter')
    ) {
        yield 'Helicopter';
    }

    if (pronouns.includes('nor/mal')
    ) {
        yield 'nor/mal';
    }
}

const hasAutomatedReports = async (db, id) => {
    return (await db.get(SQL`SELECT COUNT(*) AS c FROM reports WHERE userId = ${id} AND isAutomatic = 1`)).c > 0;
}

const router = Router();

router.get('/profile/get/:username', handleErrorAsync(async (req, res) => {
    const isSelf = req.user && req.user.username === req.params.username;
    const isAdmin = req.isGranted('users');
    const user = await req.db.get(SQL`
        SELECT
            users.id,
            users.username,
            users.email,
            users.avatarSource,
            users.bannedReason,
            users.roles != '' AS team
        FROM users
        WHERE users.usernameNorm = ${normalise(req.params.username)}
    `);

    if (!user || (user.bannedReason !== null && !isAdmin && !isSelf)) {
        return res.json({
            profiles: {},
        });
    }

    user.emailHash = md5(user.email);
    delete user.email;
    user.avatar = await avatar(req.db, user);

    return res.json({
        ...user,
        profiles: await fetchProfiles(req.db, req.params.username, isSelf),
    });
}));

router.post('/profile/save', handleErrorAsync(async (req, res) => {
    if (!req.user) {
        return res.status(401).json({error: 'Unauthorised'});
    }

    // TODO just make it a transaction...
    const ids = (await req.db.all(SQL`SELECT * FROM profiles WHERE userId = ${req.user.id} AND locale = ${global.config.locale}`)).map(row => row.id);
    if (ids.length) {
        await req.db.get(SQL`UPDATE profiles
            SET
                names = ${JSON.stringify(req.body.names)},
                pronouns = ${JSON.stringify(req.body.pronouns)},
                description = ${req.body.description},
                birthday = ${req.body.birthday || null},
                links = ${JSON.stringify(req.body.links.filter(x => !!x))},
                flags = ${JSON.stringify(req.body.flags)},
                customFlags = ${JSON.stringify(req.body.customFlags)},
                words = ${JSON.stringify(req.body.words)},
                teamName = ${req.isGranted('users') ? req.body.teamName || null : ''},
                footerName = ${req.isGranted('users') ? req.body.footerName || null : ''},
                footerAreas = ${req.isGranted('users') ? req.body.footerAreas.join(',') || null : ''},
                card = NULL
            WHERE id = ${ids[0]}
        `);
    } else {
        await req.db.get(SQL`INSERT INTO profiles (id, userId, locale, names, pronouns, description, birthday, links, flags, customFlags, words, active, teamName, footerName, footerAreas)
            VALUES (${ulid()}, ${req.user.id}, ${global.config.locale}, ${JSON.stringify(req.body.names)}, ${JSON.stringify(req.body.pronouns)},
                ${req.body.description}, ${req.body.birthday || null}, ${JSON.stringify(req.body.links.filter(x => !!x))}, ${JSON.stringify(req.body.flags)}, ${JSON.stringify(req.body.customFlags)},
                ${JSON.stringify(req.body.words)}, 1,
                ${req.isGranted('users') ? req.body.teamName || null : ''},
                ${req.isGranted('users') ? req.body.footerName || null : ''},
                ${req.isGranted('users') ? req.body.footerAreas.join(',') || null : ''}
        )`);
    }

    const sus = [...isSuspicious(req.body)];
    if (sus.length && !await hasAutomatedReports(req.db, req.user.id)) {
        await req.db.get(SQL`
            INSERT INTO reports (id, userId, reporterId, isAutomatic, comment, isHandled)
            VALUES (${ulid()}, ${req.user.id}, null, 1, ${sus.join(', ')}, 0);
        `);
    }

    if (req.body.teamName) {
        await caches.admins.invalidate();
        await caches.adminsFooter.invalidate();
    }

    return res.json(await fetchProfiles(req.db, req.user.username, true));
}));

router.post('/profile/delete/:locale', handleErrorAsync(async (req, res) => {
    await req.db.get(SQL`DELETE FROM profiles WHERE userId = ${req.user.id} AND locale = ${req.params.locale}`);

    return res.json(await fetchProfiles(req.db, req.user.username, true));
}));

router.post('/profile/report/:username', handleErrorAsync(async (req, res) => {
    const user = await req.db.get(SQL`SELECT id FROM users WHERE usernameNorm = ${normalise(req.params.username)}`);
    if (!user) {
        return res.status(400).json({error: 'Missing user'});
    }
    if (!req.body.comment) {
        return res.status(400).json({error: 'Missing comment'});
    }

    await req.db.get(SQL`
        INSERT INTO reports (id, userId, reporterId, isAutomatic, comment, isHandled)
        VALUES (${ulid()}, ${user.id}, ${req.user.id}, 0, ${req.body.comment}, 0);
    `);

    return res.json('OK');
}));

export default router;
