# User Management - Hướng Dẫn Sử Dụng

## Tổng Quan

`UserService` cung cấp các công cụ toàn diện để quản lý người dùng Zalo Official Account, bao gồm:

- 👥 **User Information** - Lấy thông tin chi tiết người dùng
- 📋 **User Lists** - Quản lý danh sách người dùng với phân trang
- 🏷️ **Tag Management** - Gắn và quản lý tags cho users
- 📊 **Custom Info** - Quản lý thông tin tùy chỉnh
- 🔄 **Bulk Operations** - Xử lý hàng loạt users

**Endpoints sử dụng:**
- User Info: `https://openapi.zalo.me/v3.0/oa/user/detail`
- User List: `https://openapi.zalo.me/v3.0/oa/user/getlist`
- Update User: `https://openapi.zalo.me/v3.0/oa/user/update`
- Custom Info: `https://openapi.zalo.me/v3.0/oa/user/getcustominfo`
- Tags: `https://openapi.zalo.me/v3.0/oa/tag/gettagsofoa`

## Khởi Tạo Service

```typescript
import { UserService } from "@warriorteam/redai-zalo-sdk";
import { ZaloClient } from "@warriorteam/redai-zalo-sdk";

const client = new ZaloClient();
const userService = new UserService(client);
```

## Các Phương Thức Chính

### 1. Lấy Thông Tin User Chi Tiết

```typescript
// Lấy thông tin chi tiết của một user
const userInfo = await userService.getUserInfo(
  accessToken,
  "user-id-here"
);

console.log("User Info:", {
  userId: userInfo.user_id,
  displayName: userInfo.display_name,
  avatar: userInfo.avatar,
  userGender: userInfo.user_gender,
  userAlias: userInfo.user_alias,
  isFollower: userInfo.is_follower,
  sharedInfo: userInfo.shared_info
});
```

**Tham số:**
- `accessToken`: Access token của OA
- `userId`: ID người dùng cần lấy thông tin

### 2. Lấy Danh Sách Users

```typescript
// Lấy danh sách users với filter
const userList = await userService.getUserList(accessToken, {
  offset: 0,
  count: 50,
  tag_name: "VIP_CUSTOMER",     // Lọc theo tag (tùy chọn)
  is_follower: true,            // Chỉ lấy followers (tùy chọn)
  last_interaction_period: "L7D" // Tương tác trong 7 ngày qua
});

console.log("Total users:", userList.total);
console.log("Count:", userList.count);
console.log("Offset:", userList.offset);

userList.users.forEach(user => {
  console.log(`${user.display_name} - ${user.user_id}`);
});
```

**Tham số:**
- `offset`: Vị trí bắt đầu (0-based)
- `count`: Số lượng users mỗi page (tối đa 50)
- `tag_name`: Lọc theo tag (tùy chọn)
- `is_follower`: true/false để lọc followers
- `last_interaction_period`: "TODAY", "YESTERDAY", "L7D", "L30D"

### 3. Lấy Tất Cả Users (Auto Pagination)

```typescript
// Lấy tất cả users với phân trang tự động
const allUsers = await userService.getAllUsers(accessToken, {
  is_follower: true,
  tag_name: "PREMIUM"
});

console.log(`Total users fetched: ${allUsers.length}`);
```

**Lưu ý:**
- Zalo giới hạn max offset = 9951 (tương ứng ~10000 users)
- Method này tự động handle pagination và warning khi vượt giới hạn

### 4. Lấy Danh Sách User IDs (Tối Ưu)

```typescript
// Chỉ lấy user IDs, không lấy thông tin chi tiết (nhanh hơn)
const userIds = await userService.getAllUserIds(accessToken, {
  is_follower: true
});

console.log(`Total user IDs: ${userIds.length}`);
```

### 5. Helper Methods

```typescript
// Lấy chỉ followers
const followers = await userService.getFollowers(accessToken, 0, 50);

// Lấy users theo tag
const vipUsers = await userService.getUsersByTag(accessToken, "VIP", 0, 50);

// Lấy users theo thời gian tương tác
const recentUsers = await userService.getUsersByInteraction(
  accessToken,
  "L7D", // 7 ngày qua
  0,
  50
);
```

## User Management Operations

### 6. Cập Nhật Thông Tin User

```typescript
// Cập nhật thông tin user
const success = await userService.updateUser(accessToken, {
  user_id: "user-id-here",
  notes: "Customer quan tâm sản phẩm cao cấp",
  // Các field khác có thể cập nhật
});

console.log("Update success:", success);
```

### 7. Xóa Thông Tin User

```typescript
// Xóa thông tin user khỏi OA (không ảnh hưởng tài khoản Zalo)
const success = await userService.deleteUserInfo(accessToken, "user-id-here");
console.log("Delete success:", success);
```

### 8. Quản Lý Custom Info

```typescript
// Lấy custom info của user
const customInfo = await userService.getUserCustomInfo(accessToken, {
  user_id: "user-id-here",
  fields_to_export: ["customer_tier", "total_spent"] // Tùy chọn
});

console.log("Custom Info:", customInfo.custom_info);

// Cập nhật custom info
const updateSuccess = await userService.updateUserCustomInfo(accessToken, {
  user_id: "user-id-here",
  custom_info: {
    customer_tier: "VIP",
    total_spent: "10000000",
    last_purchase: "2024-12-01"
  }
});
```

**Lưu ý:** Cấu trúc `custom_info` phụ thuộc vào thiết lập OA

## Tag Management

### 9. Quản Lý Tags

```typescript
// Lấy danh sách tất cả tags của OA
const tags = await userService.getLabels(accessToken);
console.log("Available tags:", tags);

// Thêm tag cho user
const addSuccess = await userService.addTagToUser(accessToken, {
  user_id: "user-id-here",
  tag_name: "VIP_CUSTOMER"
});

// Xóa tag khỏi user
const removeSuccess = await userService.removeTagFromUser(accessToken, {
  user_id: "user-id-here",
  tag_name: "OLD_TAG"
});

// Xóa tag khỏi OA (xóa hoàn toàn)
const deleteSuccess = await userService.deleteLabel(accessToken, "UNUSED_TAG");
```

### 10. Bulk Operations

```typescript
// Bulk add tag cho nhiều users
const bulkAddResult = await userService.bulkAddTag(
  accessToken,
  ["user1", "user2", "user3"],
  "FLASH_SALE_2024"
);

console.log("Success:", bulkAddResult.success);
console.log("Failed:", bulkAddResult.failed);

// Bulk remove tag
const bulkRemoveResult = await userService.bulkRemoveTag(
  accessToken,
  ["user1", "user2", "user3"],
  "OLD_CAMPAIGN"
);
```

## API Methods Summary

| Method | Description | Parameters |
|--------|-------------|------------|
| `getUserInfo` | Lấy thông tin chi tiết user | `accessToken`, `userId` |
| `getUserList` | Lấy danh sách users với pagination | `accessToken`, `request` |
| `getAllUsers` | Lấy tất cả users (auto pagination) | `accessToken`, `filters?` |
| `getAllUserIds` | Lấy tất cả user IDs (tối ưu) | `accessToken`, `filters?` |
| `updateUser` | Cập nhật thông tin user | `accessToken`, `request` |
| `deleteUserInfo` | Xóa thông tin user | `accessToken`, `userId` |
| `getUserCustomInfo` | Lấy custom info | `accessToken`, `request` |
| `updateUserCustomInfo` | Cập nhật custom info | `accessToken`, `request` |
| `getLabels` | Lấy danh sách tags | `accessToken` |
| `addTagToUser` | Thêm tag cho user | `accessToken`, `request` |
| `removeTagFromUser` | Xóa tag khỏi user | `accessToken`, `request` |
| `deleteLabel` | Xóa tag khỏi OA | `accessToken`, `tagName` |
| `getUsersByTag` | Lấy users theo tag | `accessToken`, `tagName`, `offset?`, `count?` |
| `getFollowers` | Lấy chỉ followers | `accessToken`, `offset?`, `count?` |
| `getUsersByInteraction` | Lấy users theo thời gian tương tác | `accessToken`, `period`, `offset?`, `count?` |
| `bulkAddTag` | Bulk add tag | `accessToken`, `userIds`, `tagName` |
| `bulkRemoveTag` | Bulk remove tag | `accessToken`, `userIds`, `tagName` |

## Ví Dụ Thực Tế

### 1. Customer Support System

```typescript
class CustomerSupportSystem {
  constructor(private userService: UserService, private accessToken: string) {}

  async handleNewCustomer(userId: string) {
    // Lấy thông tin customer
    const userInfo = await this.userService.getUserInfo(this.accessToken, userId);

    // Thêm tag "NEW_CUSTOMER"
    await this.userService.addTagToUser(this.accessToken, {
      user_id: userId,
      tag_name: "NEW_CUSTOMER"
    });

    // Cập nhật custom info
    await this.userService.updateUserCustomInfo(this.accessToken, {
      user_id: userId,
      custom_info: {
        registration_date: new Date().toISOString(),
        customer_tier: "STANDARD",
        total_interactions: "1"
      }
    });

    console.log(`New customer ${userInfo.display_name} processed`);
  }

  async promoteToVIP(userId: string) {
    // Remove old tags
    await this.userService.removeTagFromUser(this.accessToken, {
      user_id: userId,
      tag_name: "STANDARD"
    });

    // Add VIP tag
    await this.userService.addTagToUser(this.accessToken, {
      user_id: userId,
      tag_name: "VIP"
    });

    // Update custom info
    await this.userService.updateUserCustomInfo(this.accessToken, {
      user_id: userId,
      custom_info: {
        customer_tier: "VIP",
        promotion_date: new Date().toISOString()
      }
    });
  }
}

}
```

### 2. Bulk Campaign System

```typescript
class BulkCampaignSystem {
  constructor(private userService: UserService, private accessToken: string) {}

  async runSegmentedCampaign(campaignConfig: {
    segments: string[];
    message: string;
    batchSize?: number;
  }) {
    const results = {
      totalSent: 0,
      totalFailed: 0,
      segmentResults: new Map<string, any>()
    };

    for (const segment of campaignConfig.segments) {
      console.log(`Processing segment: ${segment}`);

      // Get users by tag
      const users = await this.userService.getUsersByTag(
        this.accessToken,
        segment,
        0,
        1000
      );

      // Bulk add campaign tag
      const userIds = users.users.map(u => u.user_id);
      const bulkResult = await this.userService.bulkAddTag(
        this.accessToken,
        userIds,
        `CAMPAIGN_${Date.now()}`
      );

      results.segmentResults.set(segment, {
        totalUsers: users.total,
        tagged: bulkResult.success.length,
        failed: bulkResult.failed.length
      });

      results.totalSent += bulkResult.success.length;
      results.totalFailed += bulkResult.failed.length;
    }

    return results;
  }
}
```

## Error Handling

```typescript
import { ZaloSDKError } from "@warriorteam/redai-zalo-sdk";

try {
  const userInfo = await userService.getUserInfo(accessToken, "user-id");
  console.log("User found:", userInfo.display_name);
} catch (error) {
  if (error instanceof ZaloSDKError) {
    switch (error.code) {
      case -216:
        console.error("Access token không hợp lệ");
        break;
      case -233:
        console.error("User không tồn tại hoặc đã unfollow");
        break;
      case -201:
        console.error("Tham số không hợp lệ");
        break;
      default:
        console.error("Lỗi khác:", error.message);
    }
  } else {
    console.error("Unexpected error:", error);
  }
}
```

## Giới Hạn API

### Zalo API Limits

1. **User List Pagination**:
   - Max offset: 9951
   - Max count per request: 50
   - Tối đa ~10000 users có thể lấy được

2. **Rate Limiting**:
   - Nên có delay giữa các requests
   - Sử dụng batch operations khi có thể

3. **Custom Info**:
   - Cấu trúc phụ thuộc vào thiết lập OA
   - Tất cả giá trị đều là string

## Best Practices

### 1. Performance Optimization

```typescript
// ✅ Sử dụng getAllUserIds cho performance tốt hơn
const userIds = await userService.getAllUserIds(accessToken);

// ✅ Batch operations
const bulkResult = await userService.bulkAddTag(
  accessToken,
  userIds.slice(0, 100),
  "NEW_TAG"
);

// ✅ Pagination với reasonable page size
const users = await userService.getUserList(accessToken, {
  offset: 0,
  count: 50 // Không quá 50
});
```

### 2. Error Handling

```typescript
// ✅ Validate user ID format
function validateUserId(userId: string): boolean {
  return /^[0-9]+$/.test(userId) && userId.length > 0;
}

// ✅ Safe operations
async function safeGetUser(userId: string) {
  if (!validateUserId(userId)) {
    throw new Error("Invalid user ID format");
  }

  try {
    return await userService.getUserInfo(accessToken, userId);
  } catch (error) {
    if (error.code === -233) {
      return null; // User not found
    }
    throw error;
  }
}
```

## Troubleshooting

### Common Issues

**Q: "User not found" error**
```
A: User có thể đã unfollow OA hoặc chặn OA.
   Kiểm tra is_follower field trước.
```

**Q: Không lấy được phone number**
```
A: Phone chỉ có khi user đã share với OA.
   Sử dụng request_user_info để yêu cầu.
```

**Q: getAllUsers không lấy hết**
```
A: Zalo giới hạn max offset = 9951.
   Chỉ lấy được ~10000 users đầu tiên.
```

**Q: Custom info không cập nhật**
```
A: Kiểm tra cấu trúc custom_info trong OA settings.
   Tất cả values phải là string.
```

## Tài Liệu Liên Quan

- [Zalo Official Account API](https://developers.zalo.me/docs/api/official-account-api)
- [User Management API](https://developers.zalo.me/docs/api/official-account-api/quan-ly-nguoi-dung)
- [Tag Management API](https://developers.zalo.me/docs/api/official-account-api/quan-ly-nhan)
- [Consultation Service](./CONSULTATION_SERVICE.md)
- [Tag Management](./TAG_MANAGEMENT.md)

