using System.Text.Json;
using Kbx.Shared.Telemetry.Generated;
using Kbx.Shared.Experiments.Generated;

namespace Kbx.Shared.Telemetry;

public sealed record KbxUxEventRequest(
    string EventName,
    string? ScreenId,
    string? ScreenVersion,
    Guid SessionId,
    Guid? TaskSessionId,
    string? AppVersion,
    string? ExperimentId,
    string? ExperimentVariant,
    DateTimeOffset OccurredAt,
    int? DurationMs,
    int? Count,
    IReadOnlyDictionary<string,string>? Attributes);

public sealed record KbxUxEventBatchRequest(IReadOnlyList<KbxUxEventRequest> Events);
public sealed record KbxUxMetricRow(string MetricKey,string Label,double? Value,string Unit,long SampleCount,double? P50=null,double? P95=null);
public sealed record KbxUxMetricsResponse(DateOnly From,DateOnly To,string? ScreenId,IReadOnlyList<KbxUxMetricRow> Metrics);

public static class KbxUxTelemetryGuard
{
    private static readonly string[] ForbiddenFragments = ["phone","address","name","orderno","customer","itemcode","barcode","keyword","query","email","businessnumber","entityid"];
    public static void Validate(KbxUxEventRequest item)
    {
        if (!KbxTelemetryCatalog.Events.TryGetValue(item.EventName,out var definition)) throw new ArgumentException($"Unknown telemetry event: {item.EventName}");
        if (definition.RequiresDuration && item.DurationMs is null) throw new ArgumentException($"{item.EventName} requires durationMs.");
        if (item.DurationMs is < 0 or > 86_400_000) throw new ArgumentOutOfRangeException(nameof(item.DurationMs));
        if (item.ExperimentId is { Length: > 160 } || item.ExperimentVariant is { Length: > 80 }) throw new ArgumentException("Experiment context is too long.");
        if ((item.ExperimentId is null) != (item.ExperimentVariant is null)) throw new ArgumentException("Experiment id and variant must be supplied together.");
        if (item.Count is < 1 or > 1_000_000) throw new ArgumentOutOfRangeException(nameof(item.Count));
        var allowed=definition.AllowedAttributes.ToHashSet(StringComparer.Ordinal);
        foreach(var pair in item.Attributes ?? new Dictionary<string,string>())
        {
            if(!allowed.Contains(pair.Key)) throw new ArgumentException($"Attribute '{pair.Key}' is not allowed for {item.EventName}.");
            if(ForbiddenFragments.Any(x=>pair.Key.Contains(x,StringComparison.OrdinalIgnoreCase))) throw new ArgumentException($"Attribute '{pair.Key}' is forbidden for telemetry.");
            if(pair.Value.Length>80) throw new ArgumentException($"Attribute value is too long: {pair.Key}");
        }
    }
}
