/**
 * Authentication Module Service
 * Business logic for user authentication and authorization
 */

// Import models
const { User } = require('../../../models');
// Import custom error classes
const { UnauthorizedError, NotFoundError, ValidationError } = require('../../../utils/errors');
// Import JWT
const jwt = require('jsonwebtoken');
// Import app configuration
const appConfig = require('../../../config/app');

/**
 * Authenticate user with username and password
 * @param {string} username - Username
 * @param {string} password - Plain text password
 * @returns {Promise<Object>} User object with token
 * @throws {UnauthorizedError} If credentials are invalid
 */
const login = async (username, password) => {
  // Find user by username
  const user = await User.findOne({
    where: { username, active: true }, // Only find active users
  });

  // If user not found, throw unauthorized error
  if (!user) {
    throw new UnauthorizedError('Invalid username or password');
  }

  // Compare provided password with stored hash
  const isPasswordValid = await user.comparePassword(password);
  
  // If password is invalid, throw unauthorized error
  if (!isPasswordValid) {
    throw new UnauthorizedError('Invalid username or password');
  }

  // Update last login timestamp
  await user.update({ last_login: new Date() });

  // Generate JWT token
  const token = jwt.sign(
    {
      id: user.id, // User ID
      username: user.username, // Username
      role: user.role, // User role
    },
    appConfig.jwt.secret, // JWT secret from config
    { expiresIn: appConfig.jwt.expiresIn } // Token expiration from config
  );

  // Return user data (password excluded by toJSON) and token
  return {
    user: user.toJSON(), // User object without password
    token, // JWT token
  };
};

/**
 * Authenticate user with PIN code (quick POS login)
 * @param {string} username - Username
 * @param {string} pinCode - PIN code
 * @returns {Promise<Object>} User object with token
 * @throws {UnauthorizedError} If credentials are invalid
 */
const loginWithPin = async (username, pinCode) => {
  // Find user by username
  const user = await User.findOne({
    where: { username, active: true }, // Only find active users
  });

  // If user not found, throw unauthorized error
  if (!user) {
    throw new UnauthorizedError('Invalid username or PIN code');
  }

  // Check if user has PIN code set
  if (!user.pin_code) {
    throw new UnauthorizedError('PIN code not configured for this user');
  }

  // Compare provided PIN with stored hash
  const isPinValid = await user.comparePin(pinCode);
  
  // If PIN is invalid, throw unauthorized error
  if (!isPinValid) {
    throw new UnauthorizedError('Invalid username or PIN code');
  }

  // Update last login timestamp
  await user.update({ last_login: new Date() });

  // Generate JWT token
  const token = jwt.sign(
    {
      id: user.id, // User ID
      username: user.username, // Username
      role: user.role, // User role
    },
    appConfig.jwt.secret, // JWT secret from config
    { expiresIn: appConfig.jwt.expiresIn } // Token expiration from config
  );

  // Return user data (password excluded by toJSON) and token
  return {
    user: user.toJSON(), // User object without password
    token, // JWT token
  };
};

/**
 * Get user by ID
 * @param {number} userId - User ID
 * @returns {Promise<Object>} User object
 * @throws {NotFoundError} If user not found
 */
const getUserById = async (userId) => {
  // Find user by ID
  const user = await User.findByPk(userId);
  
  // If user not found, throw not found error
  if (!user) {
    throw new NotFoundError('User not found');
  }

  // Return user data (password excluded by toJSON)
  return user.toJSON();
};

/**
 * Check if user has required role/permission
 * @param {string} userRole - User's role
 * @param {string} requiredRole - Required role
 * @returns {boolean} True if user has permission
 */
const hasPermission = (userRole, requiredRole) => {
  // Use User class method to check permission
  return User.hasPermission(userRole, requiredRole);
};

// Export service functions
module.exports = {
  login, // Login with username and password
  loginWithPin, // Login with username and PIN code
  getUserById, // Get user by ID
  hasPermission, // Check user permissions
};

