using Google.Protobuf;
using Grpc.Core.Interceptors;
using Microsoft.Extensions.Logging;
using CMSMicroservice.Application.Common.Interfaces;
using System.Text.RegularExpressions;

namespace CMSMicroservice.WebApi.Common.Behaviours;

public partial class LoggingBehaviour : Interceptor
{
    private readonly ILogger _logger;
    private readonly ICurrentUserService _currentUserService;

    // فیلدهایی که نباید لاگ شوند (بایت‌های تصویر / فایل)
    [GeneratedRegex(@"""(File|ImageFile|image_file|file)"":\s*\{[^}]*\}", RegexOptions.Singleline)]
    private static partial Regex BinaryFieldPattern();

    public LoggingBehaviour(ILogger<LoggingBehaviour> logger, ICurrentUserService currentUserService)
    {
        _logger = logger;
        _currentUserService = currentUserService;
    }

    public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
        TRequest request,
        ServerCallContext context,
        UnaryServerMethod<TRequest, TResponse> continuation)
    {
        var requestName = typeof(TRequest).Name;
        var userId = _currentUserService.UserId ?? string.Empty;

        // لاگ بدون بایت‌های فایل
        var safeLog = SanitizeForLog(request);
        _logger.LogInformation("gRPC Starting receiving call. Type/Method: {Type} / {Method} Request: {Name} {UserId} {Request}",
            MethodType.Unary, context.Method, requestName, userId, safeLog);

        try
        {
            return await continuation(request, context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "gRPC Request: Unhandled Exception for Request {Name} {Request}", requestName, safeLog);
            throw;
        }
    }

    /// <summary>
    /// حذف بایت‌های فایل از لاگ — جایگزینی با [BINARY DATA]
    /// </summary>
    private static string SanitizeForLog<T>(T request)
    {
        if (request is IMessage protoMessage)
        {
            var json = JsonFormatter.Default.Format(protoMessage);
            // حذف محتوای فیلدهای باینری
            json = BinaryFieldPattern().Replace(json, "\"$1\": \"[BINARY DATA]\"");
            // اگر هنوز رشته‌های base64 طولانی هست، خلاصه کن
            if (json.Length > 2000)
                return json[..2000] + "... [TRUNCATED]";
            return json;
        }
        return request?.ToString() ?? "";
    }
}
