using Serilog;

namespace adas_core.Logging;

public static class LogExecutionContext
{
    private static readonly AsyncLocal<string> AsyncLocalTraceIdentifier = new();

    public static string? TraceIdentifier => AsyncLocalTraceIdentifier.Value;

    /// Tries to set the trace identifier.
    /// 
    /// Trace identifier.
    /// If existing trace ID should be replaced (set to true ONLY if you receive and handle traced entities in a constant context)!
    public static bool TrySetTraceIdentifier(string traceIdentifier, bool force = false)
    {
        return TrySetValue(nameof(TraceIdentifier), traceIdentifier, AsyncLocalTraceIdentifier, string.IsNullOrEmpty,
            force);
    }

    private static bool TrySetValue(
        string contextPropertyName,
        string newValue,
        AsyncLocal<string> ambientHolder,
        Func<string, bool> valueInvalidator,
        bool force)

    {
        if (newValue.Equals(null) || valueInvalidator.Invoke(newValue)) return false;

        var currentValue = ambientHolder.Value;
        if (force || currentValue is null || currentValue.Equals(null) || valueInvalidator.Invoke(currentValue))
        {
            ambientHolder.Value = newValue;
            return true;
        }

        if (!currentValue.Equals(newValue))
            Log.Error(
                "Tried to set different value for {ctx}, but it is already set for this execution flow -{contextPropertyName} please, check the execution context logic! Current value: {currentValue} ; rejected value: {newValue}"
                , contextPropertyName, contextPropertyName, currentValue, newValue);

        return false;
    }
}