// EN: IAM API Service — calls IAM Service API for roles, audit, users.
// VI: IAM API Service — gọi IAM Service API cho roles, audit, users.

using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace WebClientTpos.Client.Services;

/// <summary>
/// EN: Service for calling IAM Service API (Roles, Audit, Users).
/// VI: Service để gọi IAM Service API (Roles, Audit, Users).
/// </summary>
public class IamApiService
{
    private readonly HttpClient _http;
    private static readonly JsonSerializerOptions _jsonOptions = new()
    {
        PropertyNameCaseInsensitive = true,
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
    };

    public IamApiService(HttpClient http)
    {
        _http = http;
    }

    // EN: Auth is handled by the BFF httpOnly session cookie — no manual token attachment needed.
    // VI: Auth được xử lý bởi BFF httpOnly session cookie — không cần gắn token thủ công.
    private static Task SetAuthHeader() => Task.CompletedTask;

    // ═══════════════════════════════════════════════
    // ─── ROLES ───
    // ═══════════════════════════════════════════════

    public record RoleDto(
        Guid Id,
        string Name,
        string? Description,
        [property: JsonPropertyName("isSystemRole")] bool IsSystem,
        DateTime CreatedAt,
        int? UserCount,
        List<string>? Permissions = null);

    public async Task<List<RoleDto>> GetRolesAsync()
    {
        await SetAuthHeader();
        try
        {
            var response = await _http.GetAsync("/api/iam/api/v1/roles?pageSize=50");
            if (response.IsSuccessStatusCode)
            {
                var json = await response.Content.ReadFromJsonAsync<JsonElement>(_jsonOptions);
                // EN: API returns { success, data: [...], pagination: {...} }
                // VI: API trả về { success, data: [...], pagination: {...} }
                if (json.TryGetProperty("data", out var data))
                {
                    // data is a direct array of roles
                    if (data.ValueKind == JsonValueKind.Array)
                        return data.Deserialize<List<RoleDto>>(_jsonOptions) ?? new();
                    // data might have items sub-property
                    if (data.TryGetProperty("items", out var items))
                        return items.Deserialize<List<RoleDto>>(_jsonOptions) ?? new();
                }
                if (json.TryGetProperty("items", out var items2))
                    return items2.Deserialize<List<RoleDto>>(_jsonOptions) ?? new();
                return json.Deserialize<List<RoleDto>>(_jsonOptions) ?? new();
            }
            return new();
        }
        catch { return new(); }
    }

    /// <summary>
    /// EN: Create a new role.
    /// VI: Tạo role mới.
    /// </summary>
    public async Task<(bool Success, string? Error)> CreateRoleAsync(string name, string? description)
    {
        await SetAuthHeader();
        try
        {
            var response = await _http.PostAsJsonAsync("/api/iam/api/v1/roles", new { name, description }, _jsonOptions);
            if (response.IsSuccessStatusCode) return (true, null);
            var json = await response.Content.ReadFromJsonAsync<JsonElement>(_jsonOptions);
            var msg = json.TryGetProperty("error", out var err) && err.TryGetProperty("message", out var m)
                ? m.GetString() : response.ReasonPhrase;
            return (false, msg ?? "Tạo vai trò thất bại");
        }
        catch (Exception ex) { return (false, ex.Message); }
    }

    /// <summary>
    /// EN: Update an existing role.
    /// VI: Cập nhật role.
    /// </summary>
    public async Task<(bool Success, string? Error)> UpdateRoleAsync(Guid id, string name, string? description)
    {
        await SetAuthHeader();
        try
        {
            var response = await _http.PutAsJsonAsync($"/api/iam/api/v1/roles/{id}", new { name, description }, _jsonOptions);
            if (response.IsSuccessStatusCode) return (true, null);
            var json = await response.Content.ReadFromJsonAsync<JsonElement>(_jsonOptions);
            var msg = json.TryGetProperty("error", out var err) && err.TryGetProperty("message", out var m)
                ? m.GetString() : response.ReasonPhrase;
            return (false, msg ?? "Cập nhật vai trò thất bại");
        }
        catch (Exception ex) { return (false, ex.Message); }
    }

    /// <summary>
    /// EN: Delete a role.
    /// VI: Xóa role.
    /// </summary>
    public async Task<(bool Success, string? Error)> DeleteRoleAsync(Guid id)
    {
        await SetAuthHeader();
        try
        {
            var response = await _http.DeleteAsync($"/api/iam/api/v1/roles/{id}");
            if (response.IsSuccessStatusCode) return (true, null);
            var json = await response.Content.ReadFromJsonAsync<JsonElement>(_jsonOptions);
            var msg = json.TryGetProperty("error", out var err) && err.TryGetProperty("message", out var m)
                ? m.GetString() : response.ReasonPhrase;
            return (false, msg ?? "Xóa vai trò thất bại");
        }
        catch (Exception ex) { return (false, ex.Message); }
    }

    // ═══════════════════════════════════════════════
    // ─── ROLE PERMISSIONS ───
    // ═══════════════════════════════════════════════

    /// <summary>
    /// EN: Update permissions for a role (PUT to role_claims).
    /// VI: Cập nhật permissions cho một role (PUT vào role_claims).
    /// </summary>
    public async Task<(bool Success, string? Error)> UpdateRolePermissionsAsync(Guid roleId, List<string> permissions)
    {
        try
        {
            var response = await _http.PutAsJsonAsync(
                $"/api/iam/api/v1/roles/{roleId}/permissions",
                new { permissions }, _jsonOptions);
            if (response.IsSuccessStatusCode) return (true, null);
            var json = await response.Content.ReadFromJsonAsync<JsonElement>(_jsonOptions);
            var msg = json.TryGetProperty("error", out var e) && e.TryGetProperty("message", out var m)
                ? m.GetString() : response.ReasonPhrase;
            return (false, msg ?? "Cập nhật quyền hạn thất bại");
        }
        catch (Exception ex) { return (false, ex.Message); }
    }

    // ═══════════════════════════════════════════════
    // ─── USERS ───
    // ═══════════════════════════════════════════════

    public record UserListDto(
        Guid Id,
        string Email,
        string FirstName,
        string LastName,
        string FullName,
        string? Status,
        DateTime CreatedAt,
        DateTime? LastLoginAt);

    public record UserRolesDto(string UserId, IEnumerable<string> Roles);

    /// <summary>
    /// EN: Get paginated list of users.
    /// VI: Lấy danh sách users phân trang.
    /// </summary>
    public async Task<(List<UserListDto> Users, int TotalCount)> GetUsersAsync(int page = 1, int pageSize = 20)
    {
        await SetAuthHeader();
        try
        {
            var response = await _http.GetAsync($"/api/iam/api/v1/users?pageNumber={page}&pageSize={pageSize}");
            if (response.IsSuccessStatusCode)
            {
                var json = await response.Content.ReadFromJsonAsync<JsonElement>(_jsonOptions);
                var users = new List<UserListDto>();
                var total = 0;

                if (json.TryGetProperty("data", out var data))
                {
                    if (data.ValueKind == JsonValueKind.Array)
                        users = data.Deserialize<List<UserListDto>>(_jsonOptions) ?? new();
                    else if (data.TryGetProperty("items", out var items))
                        users = items.Deserialize<List<UserListDto>>(_jsonOptions) ?? new();
                }

                if (json.TryGetProperty("pagination", out var pagination) &&
                    pagination.TryGetProperty("totalCount", out var tc))
                    total = tc.GetInt32();

                return (users, total);
            }
            return (new(), 0);
        }
        catch { return (new(), 0); }
    }

    /// <summary>
    /// EN: Get user by ID.
    /// VI: Lấy user theo ID.
    /// </summary>
    public async Task<UserListDto?> GetUserByIdAsync(Guid id)
    {
        await SetAuthHeader();
        try
        {
            var response = await _http.GetAsync($"/api/iam/api/v1/users/{id}");
            if (response.IsSuccessStatusCode)
            {
                var json = await response.Content.ReadFromJsonAsync<JsonElement>(_jsonOptions);
                if (json.TryGetProperty("data", out var data))
                    return data.Deserialize<UserListDto>(_jsonOptions);
            }
            return null;
        }
        catch { return null; }
    }

    /// <summary>
    /// EN: Get roles assigned to a user.
    /// VI: Lấy danh sách roles của user.
    /// </summary>
    public async Task<List<string>> GetUserRolesAsync(Guid userId)
    {
        await SetAuthHeader();
        try
        {
            var response = await _http.GetAsync($"/api/iam/api/v1/users/{userId}/roles");
            if (response.IsSuccessStatusCode)
            {
                var json = await response.Content.ReadFromJsonAsync<JsonElement>(_jsonOptions);
                if (json.TryGetProperty("data", out var data) &&
                    data.TryGetProperty("roles", out var roles))
                    return roles.Deserialize<List<string>>(_jsonOptions) ?? new();
            }
            return new();
        }
        catch { return new(); }
    }

    /// <summary>
    /// EN: Assign a role to a user.
    /// VI: Gán role cho user.
    /// </summary>
    public async Task<(bool Success, string? Error)> AssignRoleAsync(Guid userId, string roleName)
    {
        await SetAuthHeader();
        try
        {
            var response = await _http.PostAsJsonAsync($"/api/iam/api/v1/users/{userId}/roles", new { roleName }, _jsonOptions);
            if (response.IsSuccessStatusCode) return (true, null);
            var json = await response.Content.ReadFromJsonAsync<JsonElement>(_jsonOptions);
            var msg = json.TryGetProperty("error", out var err) && err.TryGetProperty("message", out var m)
                ? m.GetString() : response.ReasonPhrase;
            return (false, msg ?? "Gán vai trò thất bại");
        }
        catch (Exception ex) { return (false, ex.Message); }
    }

    /// <summary>
    /// EN: Remove a role from a user.
    /// VI: Xóa role khỏi user.
    /// </summary>
    public async Task<(bool Success, string? Error)> RemoveRoleAsync(Guid userId, string roleName)
    {
        await SetAuthHeader();
        try
        {
            var response = await _http.DeleteAsync($"/api/iam/api/v1/users/{userId}/roles/{Uri.EscapeDataString(roleName)}");
            if (response.IsSuccessStatusCode) return (true, null);
            var json = await response.Content.ReadFromJsonAsync<JsonElement>(_jsonOptions);
            var msg = json.TryGetProperty("error", out var err) && err.TryGetProperty("message", out var m)
                ? m.GetString() : response.ReasonPhrase;
            return (false, msg ?? "Xóa vai trò thất bại");
        }
        catch (Exception ex) { return (false, ex.Message); }
    }

    /// <summary>
    /// EN: Update user info (first name, last name).
    /// VI: Cập nhật thông tin user (tên, họ).
    /// </summary>
    public async Task<(bool Success, string? Error)> UpdateUserAsync(Guid id, string? firstName, string? lastName)
    {
        await SetAuthHeader();
        try
        {
            var response = await _http.PutAsJsonAsync($"/api/iam/api/v1/users/{id}", new { firstName, lastName }, _jsonOptions);
            if (response.IsSuccessStatusCode) return (true, null);
            var json = await response.Content.ReadFromJsonAsync<JsonElement>(_jsonOptions);
            var msg = json.TryGetProperty("error", out var err) && err.TryGetProperty("message", out var m)
                ? m.GetString() : response.ReasonPhrase;
            return (false, msg ?? "Cập nhật user thất bại");
        }
        catch (Exception ex) { return (false, ex.Message); }
    }

    /// <summary>
    /// EN: Delete (deactivate) a user.
    /// VI: Xóa (vô hiệu hóa) user.
    /// </summary>
    public async Task<(bool Success, string? Error)> DeleteUserAsync(Guid id)
    {
        await SetAuthHeader();
        try
        {
            var response = await _http.DeleteAsync($"/api/iam/api/v1/users/{id}");
            if (response.IsSuccessStatusCode) return (true, null);
            var json = await response.Content.ReadFromJsonAsync<JsonElement>(_jsonOptions);
            var msg = json.TryGetProperty("error", out var err) && err.TryGetProperty("message", out var m)
                ? m.GetString() : response.ReasonPhrase;
            return (false, msg ?? "Xóa user thất bại");
        }
        catch (Exception ex) { return (false, ex.Message); }
    }

    // ═══════════════════════════════════════════════
    // ─── AUDIT LOGS ───
    // ═══════════════════════════════════════════════

    public record AuditLogDto(
        Guid? Id, DateTime? Timestamp, string? EventType, string? ActorId,
        string? ActorEmail, string? ResourceType, string? ResourceId,
        string? Action, bool? Success, string? IpAddress);

    public async Task<List<AuditLogDto>> GetAuditLogsAsync(int take = 50)
    {
        await SetAuthHeader();
        try
        {
            var response = await _http.GetAsync($"/api/iam/api/v1/audit/logs?take={take}");
            if (response.IsSuccessStatusCode)
            {
                var json = await response.Content.ReadFromJsonAsync<JsonElement>(_jsonOptions);
                if (json.TryGetProperty("data", out var data))
                {
                    // EN: API returns { data: { logs: [...] } } or { data: { items: [...] } }
                    // VI: API trả { data: { logs: [...] } } hoặc { data: { items: [...] } }
                    if (data.TryGetProperty("logs", out var logs))
                        return logs.Deserialize<List<AuditLogDto>>(_jsonOptions) ?? new();
                    if (data.TryGetProperty("items", out var items))
                        return items.Deserialize<List<AuditLogDto>>(_jsonOptions) ?? new();
                    if (data.ValueKind == JsonValueKind.Array)
                        return data.Deserialize<List<AuditLogDto>>(_jsonOptions) ?? new();
                }
                return new();
            }
            return new();
        }
        catch { return new(); }
    }
}
