/**
 * User Feature Service - Authentication business logic with AppKit integration
 * @module {{projectName}}/user-service
 * @file src/api/features/user/user.service.ts
 *
 * @llm-rule WHEN: Need authentication business logic with JWT, validation, and database access
 * @llm-rule AVOID: Direct database calls from routes - always use service layer
 * @llm-rule NOTE: Implements authentication flow with AppKit auth, database, logger, and error patterns
 */

import { loggerClass } from '@voilajsx/appkit/logger';
import { errorClass } from '@voilajsx/appkit/error';
import { authClass } from '@voilajsx/appkit/auth';
import { model } from './user.model.js';
import type {
  UserRegisterRequest,
  UserLoginResponse,
  UserResponse,
  UserProfileUpdateRequest,
  UserUpdateRequest
} from './user.types.js';

// Initialize AppKit modules following the pattern
const logger = loggerClass.get('user-service');
const error = errorClass.get();
const auth = authClass.get();

export const userService = {
  /**
   * Validate email format
   */
  validateEmail(email: string): boolean {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  },

  /**
   * Validate password strength
   */
  validatePassword(password: string): boolean {
    return !!(password && password.length >= 6);
  },

  /**
   * Register a new user
   */
  async register(data: UserRegisterRequest): Promise<UserResponse> {
    try {
      logger.info('Processing user registration', { email: data.email, role: data.role, level: data.level });

      // Validate input
      if (!data.email || !this.validateEmail(data.email)) {
        throw error.badRequest('Valid email is required');
      }

      if (!data.password || !this.validatePassword(data.password)) {
        throw error.badRequest('Password must be at least 6 characters long');
      }

      // Check if user already exists
      const existingUser = await model.findByEmail(data.email);
      if (existingUser) {
        logger.warn('User already exists', { email: data.email });
        throw error.badRequest('User already exists with this email');
      }

      // Create user
      const user = await model.create(data);

      logger.info('User registration completed', { userId: user.id, email: user.email });
      return user;

    } catch (err: any) {
      if (err.statusCode) {
        throw err;
      }
      logger.error('Failed to register user', { data, error: err });
      throw error.serverError('Failed to register user');
    }
  },

  /**
   * Login user and generate JWT token
   */
  async login(email: string, password: string): Promise<UserLoginResponse> {
    try {
      logger.info('Processing user login', { email });

      // Validate input
      if (!email || !this.validateEmail(email)) {
        throw error.badRequest('Valid email is required');
      }

      if (!password) {
        throw error.badRequest('Password is required');
      }

      // Find user by email
      const user = await model.findByEmail(email);
      if (!user) {
        logger.warn('User not found for login', { email });
        throw error.badRequest('Invalid email or password');
      }

      logger.info('User found, verifying password', { userId: user.id, email });

      // Verify password
      const isPasswordValid = await model.verifyPassword(password, user.password);
      if (!isPasswordValid) {
        logger.warn('Invalid password for login', { email, userId: user.id });
        throw error.badRequest('Invalid email or password');
      }

      logger.info('Password verified, checking user status', { userId: user.id, isActive: user.isActive });

      // Check if user is active
      if (!user.isActive) {
        logger.warn('Inactive user login attempt', { email, userId: user.id });
        throw error.badRequest('Account is deactivated');
      }

      logger.info('User is active, generating JWT token', {
        userId: user.id,
        role: user.role,
        level: user.level,
        roleLevel: `${user.role}.${user.level}`
      });

      // Generate JWT token with detailed error handling
      let token;
      try {
        token = auth.generateLoginToken({
          userId: user.id,
          role: user.role,
          level: user.level
        });
        logger.info('JWT token generated successfully', { userId: user.id });
      } catch (tokenErr: any) {
        logger.error('JWT token generation failed', {
          userId: user.id,
          role: user.role,
          level: user.level,
          roleLevel: `${user.role}.${user.level}`,
          tokenError: tokenErr.message
        });

        // Check if it's a role validation error
        if (tokenErr.message?.includes('Invalid role.level')) {
          throw error.badRequest(`Invalid user role configuration: ${user.role}.${user.level}. Please contact administrator.`);
        }

        throw error.serverError(`Failed to generate authentication token: ${tokenErr.message}`);
      }

      // Update last login
      await model.updateLastLogin(user.id);

      // Return user data with token (exclude password)
      const { password: _, ...userWithoutPassword } = user;

      logger.info('User login completed', { userId: user.id, email });
      return {
        user: userWithoutPassword,
        token
      };

    } catch (err: any) {
      if (err.statusCode) {
        throw err;
      }

      // More specific error messages based on error type
      if (err.message?.includes('User not found')) {
        logger.error('Database error during user lookup', { email, error: err.message });
        throw error.badRequest('Invalid email or password');
      }

      if (err.message?.includes('password')) {
        logger.error('Password verification error', { email, error: err.message });
        throw error.badRequest('Invalid email or password');
      }

      if (err.message?.includes('role') || err.message?.includes('token')) {
        logger.error('Authentication system error', { email, error: err.message });
        throw error.serverError('Authentication system error. Please contact administrator.');
      }

      logger.error('Unexpected login error', { email, error: err });
      throw error.serverError('Login failed due to unexpected error. Please try again.');
    }
  },

  /**
   * Get user profile by ID
   */
  async getProfile(userId: number): Promise<UserResponse> {
    try {
      logger.info('Processing get profile request', { userId });

      const user = await model.findById(userId);
      if (!user) {
        throw error.notFound('User not found');
      }

      logger.info('Get profile completed', { userId });
      return user;

    } catch (err: any) {
      if (err.statusCode) {
        throw err;
      }
      logger.error('Failed to get user profile', { userId, error: err });
      throw error.serverError('Failed to get user profile');
    }
  },

  /**
   * Update user profile
   */
  async updateProfile(userId: number, data: UserProfileUpdateRequest): Promise<UserResponse> {
    try {
      logger.info('Processing update profile request', { userId, data });

      const user = await model.findById(userId);
      if (!user) {
        throw error.notFound('User not found');
      }

      const updatedUser = await model.update(userId, data);

      logger.info('Update profile completed', { userId });
      return updatedUser;

    } catch (err: any) {
      if (err.statusCode) {
        throw err;
      }
      logger.error('Failed to update user profile', { userId, data, error: err });
      throw error.serverError('Failed to update user profile');
    }
  },

  /**
   * Change user password
   */
  async changePassword(userId: number, currentPassword: string, newPassword: string): Promise<void> {
    try {
      logger.info('Processing change password request', { userId });

      // Validate input
      if (!currentPassword) {
        throw error.badRequest('Current password is required');
      }

      if (!newPassword || !this.validatePassword(newPassword)) {
        throw error.badRequest('New password must be at least 6 characters long');
      }

      const fullUser = await model.findById(userId);
      if (!fullUser) {
        throw error.notFound('User not found');
      }

      // Need to get user with password - model.findById excludes password
      const userWithPassword = await model.findByEmail(fullUser.email);
      if (!userWithPassword) {
        throw error.notFound('User not found');
      }

      // Verify current password
      const isCurrentPasswordValid = await model.verifyPassword(currentPassword, userWithPassword.password);
      if (!isCurrentPasswordValid) {
        throw error.badRequest('Current password is incorrect');
      }

      // Update password
      await model.updatePassword(userId, newPassword);

      logger.info('Change password completed', { userId });

    } catch (err: any) {
      if (err.statusCode) {
        throw err;
      }
      logger.error('Failed to change password', { userId, error: err });
      throw error.serverError('Failed to change password');
    }
  },

  /**
   * Request password reset
   */
  async forgotPassword(email: string): Promise<void> {
    try {
      logger.info('Processing forgot password request', { email });

      // Validate input
      if (!email || !this.validateEmail(email)) {
        throw error.badRequest('Valid email is required');
      }

      const user = await model.findByEmail(email);
      if (!user) {
        // Don't reveal if user exists
        logger.info('Password reset requested for non-existent email', { email });
        return;
      }

      // Generate reset token
      const token = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
      const expiry = new Date(Date.now() + 60 * 60 * 1000); // 1 hour

      await model.setResetToken(email, token, expiry);

      // TODO: Send email with reset token
      logger.info('Password reset token generated', { email, token });

    } catch (err: any) {
      logger.error('Failed to process forgot password', { email, error: err });
      throw error.serverError('Failed to process password reset request');
    }
  },

  /**
   * Reset password with token
   */
  async resetPassword(token: string, newPassword: string): Promise<void> {
    try {
      logger.info('Processing reset password request');

      // Validate input
      if (!token) {
        throw error.badRequest('Reset token is required');
      }

      if (!newPassword || !this.validatePassword(newPassword)) {
        throw error.badRequest('New password must be at least 6 characters long');
      }

      const user = await model.findByResetToken(token);
      if (!user) {
        throw error.badRequest('Invalid or expired reset token');
      }

      await model.updatePassword(user.id, newPassword);
      await model.clearResetToken(user.id);

      logger.info('Password reset completed', { userId: user.id });

    } catch (err: any) {
      if (err.statusCode) {
        throw err;
      }
      logger.error('Failed to reset password', { error: err });
      throw error.serverError('Failed to reset password');
    }
  },

  /**
   * Get all users (admin/moderator only)
   */
  async getAllUsers(tenantId?: string): Promise<UserResponse[]> {
    try {
      logger.info('Processing get all users request', { tenantId });

      const users = await model.findAll(tenantId);

      logger.info('Get all users completed', { count: users.length });
      return users;

    } catch (err: any) {
      logger.error('Failed to get all users', { error: err });
      throw error.serverError('Failed to retrieve users');
    }
  },

  /**
   * Update user by admin (admin only)
   */
  async updateUser(id: number, data: UserUpdateRequest): Promise<UserResponse> {
    try {
      logger.info('Processing admin update user request', { id, data });

      const user = await model.findById(id);
      if (!user) {
        throw error.notFound('User not found');
      }

      const updatedUser = await model.update(id, data);

      logger.info('Admin update user completed', { id });
      return updatedUser;

    } catch (err: any) {
      if (err.statusCode) {
        throw err;
      }
      logger.error('Failed to update user by admin', { id, data, error: err });
      throw error.serverError('Failed to update user');
    }
  },

  /**
   * Delete user (admin only)
   */
  async deleteUser(id: number): Promise<void> {
    try {
      logger.info('Processing delete user request', { id });

      const user = await model.findById(id);
      if (!user) {
        throw error.notFound('User not found');
      }

      await model.delete(id);

      logger.info('Delete user completed', { id });

    } catch (err: any) {
      if (err.statusCode) {
        throw err;
      }
      logger.error('Failed to delete user', { id, error: err });
      throw error.serverError('Failed to delete user');
    }
  }
};