const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const JWT_CONFIG = require('../config/jwt');
const { AppError } = require('../middleware/errorHandler');

const BCRYPT_ROUNDS = parseInt(process.env.BCRYPT_ROUNDS) || 12;

class AuthService {
    /**
     * Authenticate user and generate JWT token
     */
    static async login(username, password) {
        // Find user
        const user = User.getByUsername(username);

        if (!user) {
            throw new AppError('Invalid credentials', 401);
        }

        // Check if user is active
        if (!user.is_active) {
            throw new AppError('Account is deactivated', 403);
        }

        // Verify password
        const isPasswordValid = await bcrypt.compare(password, user.password_hash);

        if (!isPasswordValid) {
            throw new AppError('Invalid credentials', 401);
        }

        // Update last login
        User.updateLastLogin(user.id);

        // Generate JWT token
        const token = jwt.sign(
            {
                id: user.id,
                username: user.username,
                email: user.email,
                role: user.role_name,
                roleId: user.role_id
            },
            JWT_CONFIG.secret,
            { expiresIn: JWT_CONFIG.expiresIn }
        );

        // Return user data (without password hash) and token
        const { password_hash, ...userWithoutPassword } = user;

        return {
            user: userWithoutPassword,
            token
        };
    }

    /**
     * Change user password
     */
    static async changePassword(userId, currentPassword, newPassword) {
        // Get user with password hash (needed for verification)
        const user = User.getByIdWithPassword(userId);

        if (!user) {
            throw new AppError('User not found', 404);
        }

        // Verify current password
        const isPasswordValid = await bcrypt.compare(currentPassword, user.password_hash);

        if (!isPasswordValid) {
            throw new AppError('Current password is incorrect', 401);
        }

        // Validate new password
        this.validatePassword(newPassword);

        // Hash new password
        const newPasswordHash = await bcrypt.hash(newPassword, BCRYPT_ROUNDS);

        // Update password and remove must_change_password flag
        User.changePassword(userId, newPasswordHash, false);

        return { message: 'Password changed successfully' };
    }

    /**
     * Validate password strength
     */
    static validatePassword(password) {
        if (password.length < 8) {
            throw new AppError('Password must be at least 8 characters long', 400);
        }

        if (!/[A-Z]/.test(password)) {
            throw new AppError('Password must contain at least one uppercase letter', 400);
        }

        if (!/[a-z]/.test(password)) {
            throw new AppError('Password must contain at least one lowercase letter', 400);
        }

        if (!/[0-9]/.test(password)) {
            throw new AppError('Password must contain at least one number', 400);
        }

        if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
            throw new AppError('Password must contain at least one special character', 400);
        }

        return true;
    }

    /**
     * Hash a password
     */
    static async hashPassword(password) {
        this.validatePassword(password);
        return bcrypt.hash(password, BCRYPT_ROUNDS);
    }
}

module.exports = AuthService;
