using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;

namespace Nexus.Api.Services;

public static class OpenClawInvocationContextFactory
{
    private const int MaxMetadataLength = 128;

    public static OpenClawInvocationContext Create(
        string? actor = null,
        string? idempotencyKey = null,
        string? correlationId = null,
        string? traceParent = null,
        bool includeIdempotencyParameter = false)
    {
        var normalizedIdempotencyKey = NormalizeOrGenerate(idempotencyKey, "idem");
        var normalizedCorrelationId = NormalizeOrGenerate(correlationId, "corr");
        var normalizedActor = NormalizeActor(actor);
        var normalizedTraceParent = NormalizeTraceParent(traceParent);

        return new OpenClawInvocationContext(
            normalizedIdempotencyKey,
            normalizedCorrelationId,
            normalizedActor,
            normalizedTraceParent,
            includeIdempotencyParameter);
    }

    public static string Hash(string value)
        => Convert.ToHexStringLower(SHA256.HashData(Encoding.UTF8.GetBytes(value)));

    private static string NormalizeOrGenerate(string? value, string prefix)
    {
        var trimmed = value?.Trim();
        if (string.IsNullOrWhiteSpace(trimmed))
            return $"{prefix}_{Guid.NewGuid():N}";
        if (trimmed.Length > MaxMetadataLength)
            throw new ArgumentException($"{prefix} metadata must not exceed {MaxMetadataLength} characters.");
        if (trimmed.Any(char.IsControl))
            throw new ArgumentException($"{prefix} metadata must not contain control characters.");
        return trimmed;
    }

    private static string NormalizeActor(string? actor)
    {
        var trimmed = actor?.Trim();
        if (string.IsNullOrWhiteSpace(trimmed))
            return "nexus-system";
        if (trimmed.Length > MaxMetadataLength)
            return $"sha256:{Hash(trimmed)}";
        return trimmed.Any(char.IsControl)
            ? $"sha256:{Hash(trimmed)}"
            : trimmed;
    }

    private static string NormalizeTraceParent(string? traceParent)
    {
        var candidate = traceParent?.Trim();
        if (!string.IsNullOrWhiteSpace(candidate))
        {
            if (!OpenClawGatewayProtocol.IsValidTraceParent(candidate))
                throw new ArgumentException("traceparent must be a valid W3C trace context.", nameof(traceParent));
            return candidate;
        }

        if (Activity.Current?.Id is { } current &&
            OpenClawGatewayProtocol.IsValidTraceParent(current))
        {
            return current;
        }

        using var activity = new Activity("Nexus.OpenClaw.Invocation")
            .SetIdFormat(ActivityIdFormat.W3C);
        activity.Start();
        return activity.Id
            ?? throw new InvalidOperationException("Could not create a W3C traceparent.");
    }
}
