import { Result } from '../../../shared/types/result';
import { UserModel, IUserDocument } from '../schemas/user.schema';
import { IUser, IUserCreate, IUserUpdate } from '../entities/user.entity';
import * as bcrypt from 'bcryptjs';

export class UserService {
  /**
   * Get all active users
   */
  async getAll(): Promise<Result<IUser[]>> {
    try {
      const users = await UserModel.find({ status: 1 }).select('-password').lean();
      const convertedUsers = users.map(user => ({
        ...user,
        _id: user._id?.toString() || ''
      })) as IUser[];
      return Result.success(convertedUsers);
    } catch (error: any) {
      return Result.error('Failed to fetch users', error.message);
    }
  }

  /**
   * Get user by ID
   */
  async getById(id: string): Promise<Result<IUser | null>> {
    try {
      const user = await UserModel.findOne({ _id: id, status: 1 }).select('-password');
      if (!user) {
        return Result.error('User not found', 'User with the specified ID does not exist');
      }
      const userObj = user.toObject();
      const convertedUser = {
        ...userObj,
        _id: userObj._id?.toString() || ''
      } as IUser;
      return Result.success(convertedUser);
    } catch (error: any) {
      return Result.error('Failed to fetch user', error.message);
    }
  }

  /**
   * Get user by email
   */
  async getByEmail(email: string): Promise<Result<IUser | null>> {
    try {
      const user = await UserModel.findOne({ email: email.toLowerCase(), status: 1 });
      if (!user) {
        return Result.error('User not found', 'User with the specified email does not exist');
      }
      const userObj = user.toObject();
      const convertedUser = {
        ...userObj,
        _id: userObj._id?.toString() || ''
      } as IUser;
      return Result.success(convertedUser);
    } catch (error: any) {
      return Result.error('Failed to fetch user', error.message);
    }
  }

  /**
   * Create new user
   */
  async create(userData: IUserCreate): Promise<Result<IUser>> {
    try {
      // Check if user already exists
      const existingUser = await UserModel.findOne({
        $or: [
          { email: userData.email.toLowerCase() },
          { username: userData.username }
        ],
        status: 1
      });

      if (existingUser) {
        return Result.error('User already exists', 'A user with this email or username already exists');
      }

      // Hash password
      const saltRounds = 10;
      const hashedPassword = await bcrypt.hash(userData.password, saltRounds);

      // Create user
      const user = new UserModel({
        ...userData,
        email: userData.email.toLowerCase(),
        password: hashedPassword,
        role: userData.role || 'user',
        permissions: []
      });

      const savedUser = await user.save();
      const userObj = savedUser.toObject();
      delete userObj.password;
      
      const convertedUser = {
        ...userObj,
        _id: userObj._id?.toString() || ''
      } as IUser;

      return Result.success(convertedUser);
    } catch (error: any) {
      return Result.error('Failed to create user', error.message);
    }
  }

  /**
   * Update user
   */
  async update(id: string, userData: IUserUpdate): Promise<Result<IUser | null>> {
    try {
      const user = await UserModel.findOne({ _id: id, status: 1 });
      if (!user) {
        return Result.error('User not found', 'User with the specified ID does not exist');
      }

      // Update user
      Object.assign(user, userData);
      const updatedUser = await user.save();
      
      const userObj = updatedUser.toObject();
      delete userObj.password;
      
      const convertedUser = {
        ...userObj,
        _id: userObj._id?.toString() || ''
      } as IUser;

      return Result.success(convertedUser);
    } catch (error: any) {
      return Result.error('Failed to update user', error.message);
    }
  }

  /**
   * Delete user (soft delete)
   */
  async delete(id: string): Promise<Result<boolean>> {
    try {
      const user = await UserModel.findOne({ _id: id, status: 1 });
      if (!user) {
        return Result.error('User not found', 'User with the specified ID does not exist');
      }

      user.status = 0;
      await user.save();

      return Result.success(true);
    } catch (error: any) {
      return Result.error('Failed to delete user', error.message);
    }
  }

  /**
   * Verify user password
   */
  async verifyPassword(userId: string, password: string): Promise<Result<boolean>> {
    try {
      const user = await UserModel.findOne({ _id: userId, status: 1 });
      if (!user) {
        return Result.error('User not found', 'User with the specified ID does not exist');
      }

      const isValid = await bcrypt.compare(password, user.password);
      return Result.success(isValid);
    } catch (error: any) {
      return Result.error('Failed to verify password', error.message);
    }
  }

  /**
   * Update last login
   */
  async updateLastLogin(id: string): Promise<Result<boolean>> {
    try {
      const user = await UserModel.findOne({ _id: id, status: 1 });
      if (!user) {
        return Result.error('User not found', 'User with the specified ID does not exist');
      }

      user.lastLoginAt = new Date();
      await user.save();

      return Result.success(true);
    } catch (error: any) {
      return Result.error('Failed to update last login', error.message);
    }
  }
} 