using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Tiku.Application.Security;

namespace Tiku.Infrastructure.Tenancy;

public sealed class TenantExecutionScope(
    IServiceScopeFactory scopeFactory,
    ILogger<TenantExecutionScope> logger) : ITenantExecutionScope
{
    public Task ExecuteAsync(
        Guid? targetTenantId,
        string reason,
        Func<IServiceProvider, CancellationToken, Task> operation,
        CancellationToken cancellationToken = default)
    {
        return ExecuteAsync<object?>(
            targetTenantId,
            reason,
            async (provider, token) =>
            {
                await operation(provider, token);
                return null;
            },
            cancellationToken);
    }

    public async Task<TResult> ExecuteAsync<TResult>(
        Guid? targetTenantId,
        string reason,
        Func<IServiceProvider, CancellationToken, Task<TResult>> operation,
        CancellationToken cancellationToken = default)
    {
        ArgumentNullException.ThrowIfNull(operation);
        if (string.IsNullOrWhiteSpace(reason))
        {
            throw new ArgumentException("A system scope requires an audit reason.", nameof(reason));
        }

        await using var scope = scopeFactory.CreateAsyncScope();
        var initializer = scope.ServiceProvider.GetRequiredService<ITenantContextInitializer>();
        initializer.InitializeSystem(targetTenantId, reason);
        logger.LogWarning(
            "Entering audited system tenant scope. TargetTenantId={TargetTenantId} Reason={Reason}",
            targetTenantId,
            reason);

        return await operation(scope.ServiceProvider, cancellationToken);
    }
}
