// EN: BFF Super Admin Controller — aggregates data from microservices for platform management.
// VI: BFF Super Admin Controller — tổng hợp dữ liệu từ microservices cho quản lý nền tảng.
using Microsoft.AspNetCore.Mvc;
using System.Net.Http.Headers;
using System.Text.Json;
namespace WebClientTpos.Server.Controllers;
///
/// EN: BFF endpoints for Super Admin panel — proxies to IAM + Merchant services.
/// VI: BFF endpoints cho trang Super Admin — proxy đến IAM + Merchant services.
///
[ApiController]
[Route("api/bff/superadmin")]
public class SuperAdminController : ControllerBase
{
private readonly IHttpClientFactory _httpFactory;
private readonly ILogger _logger;
private static readonly JsonSerializerOptions _json = new()
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
public SuperAdminController(IHttpClientFactory httpFactory, ILogger logger)
{
_httpFactory = httpFactory;
_logger = logger;
}
// ═══════════════════════════════════════════════
// ─── PLATFORM STATS (Dashboard) ───
// ═══════════════════════════════════════════════
///
/// EN: Get aggregated platform statistics from multiple services.
/// VI: Lấy thống kê nền tảng tổng hợp từ nhiều services.
///
[HttpGet("stats")]
public async Task GetPlatformStats()
{
try
{
var merchantClient = CreateAuthClient("MerchantService");
var iamClient = CreateAuthClient("IamService");
// EN: Fetch data from services in parallel
// VI: Lấy dữ liệu từ services song song
var merchantStatsTask = SafeGetJson(merchantClient, "/api/v1/admin/merchants/statistics");
var usersTask = SafeGetJson(iamClient, "/api/v1/users?pageNumber=1&pageSize=1");
await Task.WhenAll(merchantStatsTask, usersTask);
var merchantStats = merchantStatsTask.Result;
var usersData = usersTask.Result;
// EN: Extract values from merchant statistics
// VI: Trích xuất giá trị từ thống kê merchants
int totalMerchants = 0, activeMerchants = 0, pendingMerchants = 0, suspendedMerchants = 0;
int totalShops = 0, activeShops = 0;
if (merchantStats != null)
{
var data = GetDataProperty(merchantStats.Value);
totalMerchants = GetInt(data, "totalMerchants");
activeMerchants = GetInt(data, "activeMerchants", GetInt(data, "active"));
pendingMerchants = GetInt(data, "pendingMerchants", GetInt(data, "pending", GetInt(data, "pendingApproval")));
suspendedMerchants = GetInt(data, "suspendedMerchants", GetInt(data, "suspended"));
totalShops = GetInt(data, "totalShops");
activeShops = GetInt(data, "activeShops");
}
// EN: Extract total users from pagination
// VI: Trích xuất tổng users từ pagination
int totalUsers = 0;
if (usersData != null)
{
if (usersData.Value.TryGetProperty("pagination", out var pg) &&
pg.TryGetProperty("totalCount", out var tc))
totalUsers = tc.GetInt32();
}
return Ok(new
{
success = true,
data = new
{
totalMerchants,
activeMerchants,
pendingMerchants,
suspendedMerchants,
totalShops,
activeShops,
totalUsers,
newUsersToday = 0,
totalOrders = 0,
ordersToday = 0,
gmvTotal = 0m,
gmvToday = 0m
}
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to fetch platform stats");
return Ok(new
{
success = true,
data = new
{
totalMerchants = 0, activeMerchants = 0, pendingMerchants = 0, suspendedMerchants = 0,
totalShops = 0, activeShops = 0, totalUsers = 0, newUsersToday = 0,
totalOrders = 0, ordersToday = 0, gmvTotal = 0m, gmvToday = 0m
}
});
}
}
// ═══════════════════════════════════════════════
// ─── MERCHANTS ───
// ═══════════════════════════════════════════════
[HttpGet("merchants")]
public async Task GetMerchants(
[FromQuery] int page = 1, [FromQuery] int pageSize = 20,
[FromQuery] string? status = null, [FromQuery] string? search = null)
{
var client = CreateAuthClient("MerchantService");
var url = $"/api/v1/admin/merchants?pageNumber={page}&pageSize={pageSize}";
if (!string.IsNullOrEmpty(status)) url += $"&status={status}";
if (!string.IsNullOrEmpty(search)) url += $"&search={Uri.EscapeDataString(search)}";
return await ProxyGet(client, url);
}
[HttpGet("merchants/{id}")]
public async Task GetMerchantDetail(Guid id)
{
var client = CreateAuthClient("MerchantService");
return await ProxyGet(client, $"/api/v1/admin/merchants/{id}");
}
[HttpPost("merchants/{id}/approve")]
public async Task ApproveMerchant(Guid id)
{
var client = CreateAuthClient("MerchantService");
return await ProxyPost(client, $"/api/v1/admin/merchants/{id}/approve");
}
[HttpPost("merchants/{id}/suspend")]
public async Task SuspendMerchant(Guid id, [FromBody] JsonElement body)
{
var client = CreateAuthClient("MerchantService");
return await ProxyPostWithBody(client, $"/api/v1/admin/merchants/{id}/suspend", body);
}
[HttpPost("merchants/{id}/reactivate")]
public async Task ReactivateMerchant(Guid id)
{
var client = CreateAuthClient("MerchantService");
return await ProxyPost(client, $"/api/v1/admin/merchants/{id}/reactivate");
}
// ═══════════════════════════════════════════════
// ─── SUBSCRIPTION PLANS (in-memory for MVP) ───
// ═══════════════════════════════════════════════
private static readonly List