# Quản Lý Bạn Bè (Friend Management)

## Tổng Quan

SDK cung cấp đầy đủ API để quản lý bạn bè trên Zalo:
- Lấy danh sách bạn bè
- Tìm kiếm người dùng  
- Gửi lời mời kết bạn
- Chấp nhận/từ chối lời mời
- Xóa bạn bè
- Quản lý biệt danh
- Chặn/bỏ chặn người dùng

## Lấy Thông Tin Bạn Bè

### 1. Danh Sách Tất Cả Bạn Bè

```typescript
try {
  const friends = await api.getAllFriends();
  console.log('Tổng số bạn bè:', friends.data.friends.length);
  
  friends.data.friends.forEach(friend => {
    console.log(`- ${friend.displayName} (${friend.userId})`);
  });
} catch (error) {
  console.error('Lỗi lấy danh sách bạn bè:', error.message);
}
```

### 2. Thông Tin Chi Tiết Người Dùng

```typescript
// Lấy thông tin một hoặc nhiều user
const userIds = ['user-id-1', 'user-id-2'];
const userInfo = await api.getUserInfo(userIds);

userInfo.data.forEach(user => {
  console.log(`Tên: ${user.displayName}`);
  console.log(`Avatar: ${user.avatar}`);
  console.log(`Giới tính: ${user.gender === 0 ? 'Nam' : 'Nữ'}`);
  console.log(`Trạng thái: ${user.isOnline ? 'Online' : 'Offline'}`);
});
```

### 3. Thông Tin Tài Khoản Của Mình

```typescript
// Lấy ID của chính mình
const myId = await api.getOwnId();
console.log('ID của tôi:', myId);

// Lấy thông tin chi tiết tài khoản
const accountInfo = await api.fetchAccountInfo();
console.log('Thông tin tài khoản:', accountInfo);
```

## Tìm Kiếm Người Dùng

### 1. Tìm Kiếm Cơ Bản

```typescript
const searchResults = await api.findUser('Nguyễn Văn A');
console.log(`Tìm thấy ${searchResults.data.length} kết quả:`);

searchResults.data.forEach(user => {
  console.log(`- ${user.displayName} (ID: ${user.userId})`);
  console.log(`  Avatar: ${user.avatar}`);
  console.log(`  Có thể kết bạn: ${user.canAddFriend ? 'Có' : 'Không'}`);
});
```

### 2. Tìm Kiếm Nâng Cao

```typescript
async function advancedUserSearch(query: string, options: {
  maxResults?: number;
  filterOnline?: boolean;
  filterCanAddFriend?: boolean;
} = {}) {
  try {
    const results = await api.findUser(query);
    let filteredResults = results.data;
    
    // Lọc theo trạng thái online
    if (options.filterOnline) {
      filteredResults = filteredResults.filter(user => user.isOnline);
    }
    
    // Lọc theo khả năng kết bạn
    if (options.filterCanAddFriend) {
      filteredResults = filteredResults.filter(user => user.canAddFriend);
    }
    
    // Giới hạn số kết quả
    if (options.maxResults) {
      filteredResults = filteredResults.slice(0, options.maxResults);
    }
    
    return filteredResults;
  } catch (error) {
    console.error('Lỗi tìm kiếm:', error.message);
    return [];
  }
}

// Sử dụng
const users = await advancedUserSearch('John', {
  maxResults: 10,
  filterCanAddFriend: true
});
```

## Gửi Lời Mời Kết Bạn

### 1. Gửi Lời Mời Cơ Bản

```typescript
try {
  const result = await api.sendFriendRequest('user-id', 'Xin chào! Kết bạn nhé!');
  console.log('✅ Đã gửi lời mời kết bạn');
} catch (error) {
  console.error('❌ Lỗi gửi lời mời:', error.message);
}
```

### 2. Gửi Lời Mời Hàng Loạt

```typescript
async function sendBulkFriendRequests(userIds: string[], message: string = 'Xin chào!') {
  const results = [];
  const errors = [];
  
  for (const [index, userId] of userIds.entries()) {
    try {
      console.log(`Gửi lời mời ${index + 1}/${userIds.length} cho ${userId}...`);
      
      const result = await api.sendFriendRequest(userId, message);
      results.push({ userId, success: true });
      
      // Delay giữa các requests để tránh spam
      if (index < userIds.length - 1) {
        await new Promise(resolve => setTimeout(resolve, 2000));
      }
    } catch (error) {
      errors.push({ userId, error: error.message });
    }
  }
  
  console.log(`✅ Gửi thành công: ${results.length}`);
  console.log(`❌ Gửi thất bại: ${errors.length}`);
  
  return { results, errors };
}
```

### 3. Hủy Lời Mời Đã Gửi

```typescript
// Lấy danh sách lời mời đã gửi
const sentRequests = await api.getSentFriendRequest();
console.log('Lời mời đã gửi:', sentRequests.data.length);

// Hủy lời mời cụ thể
await api.undoFriendRequest('user-id');
console.log('✅ Đã hủy lời mời kết bạn');
```

## Xử Lý Lời Mời Nhận Được

### 1. Lấy Danh Sách Lời Mời

```typescript
const receivedRequests = await api.getReceivedFriendRequests();
console.log(`Có ${receivedRequests.data.length} lời mời kết bạn:`);

receivedRequests.data.forEach(request => {
  console.log(`- Từ: ${request.displayName} (${request.userId})`);
  console.log(`  Lời nhắn: ${request.message || 'Không có'}`);
  console.log(`  Thời gian: ${new Date(request.timestamp).toLocaleString()}`);
});
```

### 2. Chấp Nhận Lời Mời

```typescript
// Chấp nhận lời mời cụ thể
await api.acceptFriendRequest('user-id');
console.log('✅ Đã chấp nhận lời mời kết bạn');
```

### 3. Xử Lý Lời Mời Tự Động

```typescript
async function autoProcessFriendRequests(options: {
  autoAccept?: boolean;
  blacklist?: string[];
  whitelist?: string[];
  maxRequestsPerDay?: number;
}) {
  try {
    const requests = await api.getReceivedFriendRequests();
    let processedCount = 0;
    
    for (const request of requests.data) {
      // Kiểm tra blacklist
      if (options.blacklist?.includes(request.userId)) {
        console.log(`🚫 Bỏ qua ${request.displayName} (trong blacklist)`);
        continue;
      }
      
      // Kiểm tra whitelist
      if (options.whitelist && !options.whitelist.includes(request.userId)) {
        console.log(`⏭️ Bỏ qua ${request.displayName} (không trong whitelist)`);
        continue;
      }
      
      // Kiểm tra giới hạn số lượng
      if (options.maxRequestsPerDay && processedCount >= options.maxRequestsPerDay) {
        console.log('⏹️ Đã đạt giới hạn xử lý cho ngày hôm nay');
        break;
      }
      
      if (options.autoAccept) {
        await api.acceptFriendRequest(request.userId);
        console.log(`✅ Đã chấp nhận kết bạn với ${request.displayName}`);
        processedCount++;
        
        // Delay để tránh spam
        await new Promise(resolve => setTimeout(resolve, 1000));
      }
    }
    
    console.log(`🎉 Đã xử lý ${processedCount} lời mời kết bạn`);
  } catch (error) {
    console.error('❌ Lỗi xử lý lời mời:', error.message);
  }
}

// Sử dụng
await autoProcessFriendRequests({
  autoAccept: true,
  maxRequestsPerDay: 10,
  blacklist: ['spam-user-id-1', 'spam-user-id-2']
});
```

## Quản Lý Bạn Bè

### 1. Xóa Bạn Bè

```typescript
try {
  await api.removeFriend('user-id');
  console.log('✅ Đã xóa bạn bè');
} catch (error) {
  console.error('❌ Lỗi xóa bạn bè:', error.message);
}
```

### 2. Quản Lý Biệt Danh

```typescript
// Đặt biệt danh cho bạn bè
await api.changeFriendAlias('user-id', 'Biệt danh mới');
console.log('✅ Đã đổi biệt danh');

// Xóa biệt danh
await api.removeFriendAlias('user-id');
console.log('✅ Đã xóa biệt danh');

// Lấy danh sách biệt danh
const aliasList = await api.getAliasList();
aliasList.data.forEach(alias => {
  console.log(`${alias.displayName}: ${alias.alias}`);
});
```

### 3. Chặn và Bỏ Chặn

```typescript
// Chặn người dùng
await api.blockUser('user-id');
console.log('🚫 Đã chặn người dùng');

// Bỏ chặn
await api.unblockUser('user-id');
console.log('✅ Đã bỏ chặn người dùng');

// Chặn xem feed (không hiển thị bài viết của họ)
await api.blockViewFeed('user-id');
console.log('🚫 Đã chặn xem feed');
```

## Trạng Thái Online

### 1. Kiểm Tra Trạng Thái

```typescript
// Kiểm tra lần cuối online
const lastOnline = await api.lastOnline(['user-id-1', 'user-id-2']);
lastOnline.data.forEach(user => {
  if (user.isOnline) {
    console.log(`${user.userId}: Đang online`);
  } else {
    const lastSeen = new Date(user.lastOnlineTime);
    console.log(`${user.userId}: Lần cuối ${lastSeen.toLocaleString()}`);
  }
});
```

### 2. Monitor Online Status

```typescript
class OnlineStatusMonitor {
  private monitoredUsers: Set<string> = new Set();
  private statusCache: Map<string, boolean> = new Map();
  private interval: NodeJS.Timeout | null = null;
  
  addUser(userId: string) {
    this.monitoredUsers.add(userId);
  }
  
  removeUser(userId: string) {
    this.monitoredUsers.delete(userId);
    this.statusCache.delete(userId);
  }
  
  async startMonitoring(intervalMs: number = 60000) {
    this.interval = setInterval(async () => {
      try {
        const userIds = Array.from(this.monitoredUsers);
        if (userIds.length === 0) return;
        
        const statusData = await api.lastOnline(userIds);
        
        statusData.data.forEach(user => {
          const wasOnline = this.statusCache.get(user.userId);
          const isOnline = user.isOnline;
          
          if (wasOnline !== isOnline) {
            console.log(`📱 ${user.userId} ${isOnline ? 'đã online' : 'đã offline'}`);
            this.statusCache.set(user.userId, isOnline);
          }
        });
      } catch (error) {
        console.error('❌ Lỗi monitor online status:', error.message);
      }
    }, intervalMs);
  }
  
  stopMonitoring() {
    if (this.interval) {
      clearInterval(this.interval);
      this.interval = null;
    }
  }
}

// Sử dụng
const monitor = new OnlineStatusMonitor();
monitor.addUser('friend-id-1');
monitor.addUser('friend-id-2');
monitor.startMonitoring(30000); // Check mỗi 30 giây
```

## Báo Cáo và Thống Kê

### 1. Thống Kê Bạn Bè

```typescript
async function getFriendStats() {
  try {
    const friends = await api.getAllFriends();
    const friendList = friends.data.friends;
    
    const stats = {
      total: friendList.length,
      online: 0,
      male: 0,
      female: 0,
      withAvatar: 0,
      canMessage: 0
    };
    
    // Lấy thông tin chi tiết để thống kê
    const userIds = friendList.map(f => f.userId);
    const detailInfo = await api.getUserInfo(userIds);
    const onlineStatus = await api.lastOnline(userIds);
    
    detailInfo.data.forEach(user => {
      if (user.gender === 0) stats.male++;
      else stats.female++;
      
      if (user.avatar) stats.withAvatar++;
      if (user.canMessage) stats.canMessage++;
    });
    
    onlineStatus.data.forEach(user => {
      if (user.isOnline) stats.online++;
    });
    
    console.log('📊 Thống kê bạn bè:');
    console.log(`   Tổng số: ${stats.total}`);
    console.log(`   Online: ${stats.online} (${(stats.online/stats.total*100).toFixed(1)}%)`);
    console.log(`   Nam: ${stats.male} (${(stats.male/stats.total*100).toFixed(1)}%)`);
    console.log(`   Nữ: ${stats.female} (${(stats.female/stats.total*100).toFixed(1)}%)`);
    console.log(`   Có avatar: ${stats.withAvatar} (${(stats.withAvatar/stats.total*100).toFixed(1)}%)`);
    console.log(`   Có thể nhắn tin: ${stats.canMessage} (${(stats.canMessage/stats.total*100).toFixed(1)}%)`);
    
    return stats;
  } catch (error) {
    console.error('❌ Lỗi lấy thống kê:', error.message);
    return null;
  }
}

await getFriendStats();
```

### 2. Tìm Bạn Chung

```typescript
async function findMutualFriends(userId: string) {
  try {
    // Lấy danh sách bạn bè của mình
    const myFriends = await api.getAllFriends();
    const myFriendIds = new Set(myFriends.data.friends.map(f => f.userId));
    
    // Lấy thông tin user target (cần phương pháp khác vì API không public)
    // Đây là ví dụ logic, cần implement phù hợp với API có sẵn
    
    console.log(`🤝 Tìm bạn chung với user ${userId}`);
    // Logic tìm bạn chung tùy thuộc vào API có sẵn
    
  } catch (error) {
    console.error('❌ Lỗi tìm bạn chung:', error.message);
  }
}
```

## Backup và Restore

### 1. Backup Danh Sách Bạn Bè

```typescript
import fs from 'fs/promises';

async function backupFriends(filePath: string = './friends-backup.json') {
  try {
    console.log('💾 Đang backup danh sách bạn bè...');
    
    const friends = await api.getAllFriends();
    const friendIds = friends.data.friends.map(f => f.userId);
    
    // Lấy thông tin chi tiết
    const detailInfo = await api.getUserInfo(friendIds);
    const aliases = await api.getAliasList();
    
    const backup = {
      timestamp: new Date().toISOString(),
      totalFriends: friends.data.friends.length,
      friends: detailInfo.data,
      aliases: aliases.data
    };
    
    await fs.writeFile(filePath, JSON.stringify(backup, null, 2));
    console.log(`✅ Đã backup ${backup.totalFriends} bạn bè vào ${filePath}`);
    
    return backup;
  } catch (error) {
    console.error('❌ Lỗi backup:', error.message);
    throw error;
  }
}

// Sử dụng
await backupFriends('./backup/friends-' + new Date().toISOString().split('T')[0] + '.json');
```

### 2. So Sánh Thay Đổi

```typescript
async function compareFriendsList(backupPath: string) {
  try {
    const backupData = JSON.parse(await fs.readFile(backupPath, 'utf8'));
    const currentFriends = await api.getAllFriends();
    
    const backupIds = new Set(backupData.friends.map((f: any) => f.userId));
    const currentIds = new Set(currentFriends.data.friends.map(f => f.userId));
    
    const newFriends = [...currentIds].filter(id => !backupIds.has(id));
    const removedFriends = [...backupIds].filter(id => !currentIds.has(id));
    
    console.log('📊 So sánh thay đổi danh sách bạn bè:');
    console.log(`   Backup: ${backupData.totalFriends} bạn bè (${backupData.timestamp})`);
    console.log(`   Hiện tại: ${currentFriends.data.friends.length} bạn bè`);
    console.log(`   Bạn mới: ${newFriends.length}`);
    console.log(`   Bạn đã xóa: ${removedFriends.length}`);
    
    if (newFriends.length > 0) {
      console.log('   👥 Bạn bè mới:');
      const newFriendsInfo = await api.getUserInfo(newFriends);
      newFriendsInfo.data.forEach(friend => {
        console.log(`     - ${friend.displayName} (${friend.userId})`);
      });
    }
    
    if (removedFriends.length > 0) {
      console.log('   👋 Bạn bè đã xóa:');
      removedFriends.forEach(userId => {
        const friend = backupData.friends.find((f: any) => f.userId === userId);
        console.log(`     - ${friend?.displayName || 'Unknown'} (${userId})`);
      });
    }
    
    return { newFriends, removedFriends };
  } catch (error) {
    console.error('❌ Lỗi so sánh:', error.message);
    return null;
  }
}
```

## Utility Classes

### 1. Friend Manager

```typescript
class FriendManager {
  private api: any;
  
  constructor(api: any) {
    this.api = api;
  }
  
  async searchAndAdd(query: string, message: string = 'Xin chào!', maxResults: number = 5) {
    try {
      const results = await this.api.findUser(query);
      const candidates = results.data
        .filter((user: any) => user.canAddFriend)
        .slice(0, maxResults);
      
      console.log(`🔍 Tìm thấy ${candidates.length} ứng viên có thể kết bạn:`);
      
      for (const user of candidates) {
        console.log(`   - ${user.displayName} (${user.userId})`);
        
        try {
          await this.api.sendFriendRequest(user.userId, message);
          console.log(`     ✅ Đã gửi lời mời`);
        } catch (error) {
          console.log(`     ❌ Lỗi: ${error.message}`);
        }
        
        // Delay giữa các request
        await new Promise(resolve => setTimeout(resolve, 2000));
      }
    } catch (error) {
      console.error('❌ Lỗi tìm kiếm và kết bạn:', error.message);
    }
  }
  
  async cleanupFriends(options: {
    removeInactive?: boolean;
    inactiveDays?: number;
    removeNoAvatar?: boolean;
    dryRun?: boolean;
  } = {}) {
    const friends = await this.api.getAllFriends();
    const friendIds = friends.data.friends.map((f: any) => f.userId);
    
    const detailInfo = await this.api.getUserInfo(friendIds);
    const onlineStatus = await this.api.lastOnline(friendIds);
    
    const toRemove = [];
    
    for (const friend of detailInfo.data) {
      const online = onlineStatus.data.find((u: any) => u.userId === friend.userId);
      
      // Kiểm tra không hoạt động
      if (options.removeInactive && online && !online.isOnline) {
        const daysSinceOnline = (Date.now() - online.lastOnlineTime) / (1000 * 60 * 60 * 24);
        if (daysSinceOnline > (options.inactiveDays || 30)) {
          toRemove.push({ user: friend, reason: `Không online ${daysSinceOnline.toFixed(0)} ngày` });
        }
      }
      
      // Kiểm tra không có avatar
      if (options.removeNoAvatar && !friend.avatar) {
        toRemove.push({ user: friend, reason: 'Không có avatar' });
      }
    }
    
    console.log(`🧹 Sẽ xóa ${toRemove.length} bạn bè:`);
    toRemove.forEach(item => {
      console.log(`   - ${item.user.displayName}: ${item.reason}`);
    });
    
    if (!options.dryRun) {
      for (const item of toRemove) {
        try {
          await this.api.removeFriend(item.user.userId);
          console.log(`   ✅ Đã xóa ${item.user.displayName}`);
          await new Promise(resolve => setTimeout(resolve, 1000));
        } catch (error) {
          console.log(`   ❌ Lỗi xóa ${item.user.displayName}: ${error.message}`);
        }
      }
    } else {
      console.log('🔍 Chế độ dry run - không thực hiện xóa');
    }
  }
}

// Sử dụng
const friendManager = new FriendManager(api);
await friendManager.searchAndAdd('developer', 'Chào bạn! Mình cũng là developer');
await friendManager.cleanupFriends({
  removeInactive: true,
  inactiveDays: 60,
  dryRun: true
});
```

## Best Practices

### 1. Rate Limiting

```typescript
class FriendRequestLimiter {
  private requestCount = 0;
  private lastResetTime = Date.now();
  private readonly maxRequestsPerHour = 10;
  private readonly resetInterval = 60 * 60 * 1000; // 1 hour
  
  canSendRequest(): boolean {
    const now = Date.now();
    
    // Reset counter nếu đã qua 1 giờ
    if (now - this.lastResetTime >= this.resetInterval) {
      this.requestCount = 0;
      this.lastResetTime = now;
    }
    
    return this.requestCount < this.maxRequestsPerHour;
  }
  
  async sendFriendRequest(userId: string, message: string) {
    if (!this.canSendRequest()) {
      const timeUntilReset = this.resetInterval - (Date.now() - this.lastResetTime);
      const minutesLeft = Math.ceil(timeUntilReset / (60 * 1000));
      throw new Error(`Đã đạt giới hạn gửi lời mời. Thử lại sau ${minutesLeft} phút.`);
    }
    
    try {
      await api.sendFriendRequest(userId, message);
      this.requestCount++;
      console.log(`✅ Đã gửi lời mời (${this.requestCount}/${this.maxRequestsPerHour})`);
    } catch (error) {
      throw error;
    }
  }
}
```

### 2. Error Handling

```typescript
async function safeFriendOperation<T>(
  operation: () => Promise<T>,
  operationName: string,
  retries: number = 3
): Promise<T | null> {
  for (let attempt = 1; attempt <= retries; attempt++) {
    try {
      const result = await operation();
      return result;
    } catch (error) {
      console.error(`❌ ${operationName} thất bại (lần ${attempt}):`, error.message);
      
      if (attempt === retries) {
        console.error(`💥 ${operationName} thất bại sau ${retries} lần thử`);
        return null;
      }
      
      // Exponential backoff
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
  
  return null;
}

// Sử dụng
const friends = await safeFriendOperation(
  () => api.getAllFriends(),
  'Lấy danh sách bạn bè'
);
```

## Lưu Ý Quan Trọng

1. **Rate Limiting**: Giới hạn số lượng request để tránh bị chặn
2. **Privacy**: Một số thông tin có thể không accessible tùy thuộc privacy settings
3. **Permissions**: Cần quyền thích hợp để thực hiện các thao tác
4. **Spam Prevention**: Tránh gửi quá nhiều lời mời trong thời gian ngắn  
5. **Data Backup**: Định kỳ backup danh sách bạn bè quan trọng
6. **Error Handling**: Luôn xử lý lỗi và có phương án retry
7. **User Experience**: Thông báo rõ ràng cho user về các thao tác đang thực hiện