const bcrypt = require('bcrypt');
const sequelize = require('../config/db.js');
const models = require('../models/index.js');

const SALT_ROUNDS = 10;

const parseArgs = (argv) => {
    const args = {};

    for (let i = 2; i < argv.length; i += 1) {
        const arg = argv[i];

        if (!arg.startsWith('--')) {
            continue;
        }

        const key = arg.slice(2);
        const value = argv[i + 1];

        if (!value || value.startsWith('--')) {
            args[key] = true;
            continue;
        }

        args[key] = value;
        i += 1;
    }

    return args;
};

const printHelp = () => {
    console.log('Reset a user password from CLI');
    console.log('');
    console.log('Usage:');
    console.log('  npm run reset:password -- --username <username> --password <newPassword>');
    console.log('  npm run reset:password -- --id <userId> --password <newPassword>');
    console.log('');
    console.log('Options:');
    console.log('  --username   Username of target user');
    console.log('  --id         Numeric user id of target user');
    console.log('  --password   New plaintext password');
    console.log('  --help       Show this help text');
};

const main = async () => {
    const args = parseArgs(process.argv);

    if (args.help) {
        printHelp();
        return;
    }

    const hasUsername = typeof args.username === 'string' && args.username.trim().length > 0;
    const hasId = typeof args.id === 'string' && args.id.trim().length > 0;
    const hasPassword = typeof args.password === 'string' && args.password.length > 0;

    if ((!hasUsername && !hasId) || !hasPassword) {
        printHelp();
        process.exitCode = 1;
        return;
    }

    if (args.password.length < 8) {
        console.error('Password must be at least 8 characters.');
        process.exitCode = 1;
        return;
    }

    const where = hasId
        ? { id: Number(args.id) }
        : { username: args.username.trim().toLowerCase() };

    if (hasId && Number.isNaN(where.id)) {
        console.error('Invalid --id. It must be a number.');
        process.exitCode = 1;
        return;
    }

    const user = await models.User.findOne({
        where,
        attributes: ['id', 'username']
    });

    if (!user) {
        console.error('User not found.');
        process.exitCode = 1;
        return;
    }

    const hashedPassword = await bcrypt.hash(args.password, SALT_ROUNDS);

    await models.User.update(
        { password: hashedPassword },
        { where: { id: user.id } }
    );

    console.log(`Password updated for user ${user.username} (id: ${user.id}).`);
};

main()
    .catch((err) => {
        const msg = err?.message || String(err);
        if (msg.includes("Data too long for column 'password'")) {
            console.error('Password reset failed: users.password column is too short for bcrypt hash.');
            console.error('Run this once on DB: ALTER TABLE users MODIFY password VARCHAR(250) NOT NULL;');
        } else {
            console.error('Password reset failed:', msg);
        }
        process.exitCode = 1;
    })
    .finally(async () => {
        try {
            await sequelize.close();
        } catch (err) {
            // Best effort close only.
        }
    });
