/*Canopy - The next generation of stoner streaming software
Copyright (C) 2024-2025 Rainbownapkin and the TTN Community

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.*/

//NPM Imports
const { checkSchema } = require('express-validator');
const {sanitizeUrl} = require("@braintree/sanitize-url");

//local imports
const {isRank} = require('./permissionsValidator');

module.exports.user = function(field = 'user'){
    return checkSchema({
        [field]: {
            escape: true,
            trim: true,
            //Caution: Nerd Rant
            //isAlphanumerics only takes locale for the option flag in schemas for some reason...
            matches: {
                //See this is the shit I'm talking about, WHY IS THIS CALLED OPTIONS? IT SHOULD BE PATTERN
                //OPTIONS IS SUPPOSED TO BE AN OBJECT THAT PASSES EXTRA VALUES THATS LITERALLY HOW EVERYTHING ELSE IN THIS FUCKING LIBRARY WORKS
                //WHO FUCKING WROTE THIS SHIT!?!?!?!?!
                //HOW IS THIS ACCEPTED ON ONE OF THE MOST WIDELY USED VALIDATION LIBRARIES ON THE WEB!??!?!?!!?
                //IT'S NOT EVEN FUCKING DOCUMENTED ANYWHERE!!!!!!!!!!!!
                //WEBDEVS, GET YOUR FUCKING SHIT TOGETHER, FUCK!
                options: [/^[A-Za-z0-9-_]+$/],
                errorMessage: "Usernames can only contain numbers, letters, underscores, and dashes."
            },
            //matches: /^[A-Za-z0-9-_]+$/,
            isLength: {
                options: {
                    min: 1,
                    max: 22
                },
                errorMessage: "Usernames must be between 1 and 22 characters." 
            },
        }
    });
}

function getPassSchema(field = 'pass'){
    //Heavily simplified from previous versions.
    //Trimming passwords is iffy, and escaping them is a down-right bad idea
    return {
        [field]: {
            notEmpty: true,
        }
    }
}

module.exports.pass = function(field = 'pass'){
    return checkSchema(getPassSchema(field));
}

module.exports.securePass = function(field = 'pass'){
    const schema = getPassSchema(field);

    schema[field].isStrongPassword = {
        options: {
            minLength: 8,
            minLowercase: 1,
            minUppercase: 1,
            minNumbers: 1,
            minSymbols: 1
        },
        errorMessage: "Passwords must contain 8 characters, including at least one: Upper, Lower, Number, and Special char."
    }

    return checkSchema(schema);
}

module.exports.email = function(field = 'email'){
    return checkSchema({
        [field]: {
            optional: true,
            isEmail: {
                errorMessage: "Invalid E-Mail Address"
            },
            normalizeEmail: true
        }
    });
}

module.exports.img = function(field = 'img'){
    return checkSchema({
        [field]: {
            optional: true,
            isURL: {
                options: {
                    require_tld: false,
                    require_host: false,
                    require_valid_protocol: true
                },
                errorMessage: "Invalid URL."
            },
            trim: true,
            customSanitizer: {
                options: sanitizeUrl
            }
        }
    });
}

module.exports.pronouns = function(field = 'pronouns'){
    return checkSchema({
        [field]: {
            optional: true,
            trim: true,
            isLength: {
                options: {
                    min: 0,
                    max: 15
                },
                errorMessage: "Pronouns must be under 15 characters."
            },
            escape: true
        }
    });
}

module.exports.signature = function(field = 'signature'){
    return checkSchema({
        [field]: {
            optional: true,
            trim: true,
            isLength: {
                options: {
                    min: 1,
                    max: 25
                },
                errorMessage: "Signature must be between 1 and 25 characters."
            },
            escape: true
        }
    });
}

module.exports.bio = function(field = 'bio'){
    return checkSchema({
        [field]: {
            optional: true,
            trim: true,
            isLength: {
                options: {
                    min: 1,
                    max: 1000
                },
                errorMessage: "Bio must be between 1 and 1000 characters."
            },
            escape: true
        }
    });
}

module.exports.rank = function(field = 'rank'){
    return checkSchema({
        [field]: {
            escape: true,
            trim: true,
            custom: {
                options: isRank,
            },
            errorMessage: "Invalid rank."
        }
    });
}

const securityTokenSchema = {
    escape: true,
    trim: true,
    isHexadecimal: true,
    isLength: {
        options: {
            min: 64,
            max: 64
        }
    },
    errorMessage: "Invalid security token."
}

module.exports.securityToken = function(field = 'token'){
    return checkSchema({[field]:securityTokenSchema});
}

module.exports.rememberMeID = function(field = 'rememberme.id'){
    return checkSchema({
        [field]:{
            in: ['cookies'],
            optional: true,
            isUUID: true
        }
    })
}

module.exports.rememberMeToken = function(field = 'rememberme.token'){
    //Create our own schema with blackjack and hookers
    const tokenSchema = structuredClone(securityTokenSchema);

    //Modify as needed
    tokenSchema.in = ['cookies'];
    tokenSchema.optional = true;

    //Return the validator
    return checkSchema({[field]:tokenSchema});
}