using System.Text.Json;
using Backend.Contracts;
using Backend.Domain;

namespace Backend.Endpoints;

public static class AdminRiskFlagMappings
{
    public static AdminRiskFlagDto ToDto(RiskFlag item) =>
        new(
            item.Id,
            item.Source,
            item.Type,
            item.Severity,
            item.Status,
            item.Summary,
            item.TwitchUserId,
            item.CreatedFromIp,
            item.CreatedAt,
            item.MetadataJson,
            item.ReviewNote,
            item.ReviewedByTwitchId,
            item.ReviewedAt,
            BuildEntityLinks(item));

    public static AdminRiskEntityLinkDto[] BuildEntityLinks(RiskFlag item)
    {
        var links = ReadExplicitLinks(item.MetadataJson).ToList();
        if (links.Count > 0)
        {
            return links.ToArray();
        }

        var query = Uri.EscapeDataString(item.TwitchUserId ?? item.Summary);
        return item.Source.ToLowerInvariant() switch
        {
            "clip" => [new AdminRiskEntityLinkDto("Clips öffnen", "clip", item.TwitchUserId ?? item.Id.ToString(), $"/admin/clips?query={query}")],
            "nomination" => [new AdminRiskEntityLinkDto("Reviews öffnen", "nomination", item.TwitchUserId ?? item.Id.ToString(), $"/admin/reviews?query={query}")],
            "vote" => [new AdminRiskEntityLinkDto("Voting-Analytics öffnen", "vote", item.TwitchUserId ?? item.Id.ToString(), $"/admin/analytics?query={query}")],
            "login" => [new AdminRiskEntityLinkDto("Audit-Log öffnen", "session", item.TwitchUserId ?? item.Id.ToString(), $"/admin/users-logs?query={query}")],
            _ => [],
        };
    }

    private static IEnumerable<AdminRiskEntityLinkDto> ReadExplicitLinks(string metadataJson)
    {
        if (string.IsNullOrWhiteSpace(metadataJson))
        {
            yield break;
        }

        JsonDocument document;
        try
        {
            document = JsonDocument.Parse(metadataJson);
        }
        catch (JsonException)
        {
            yield break;
        }

        using (document)
        {
            if (TryReadEntityLinks(document.RootElement, out var entityLinks))
            {
                foreach (var link in entityLinks)
                {
                    yield return link;
                }
            }
        }
    }

    private static bool TryReadEntityLinks(JsonElement root, out AdminRiskEntityLinkDto[] links)
    {
        links = [];
        if (root.ValueKind != JsonValueKind.Object || !TryGetProperty(root, "entityLinks", out var entityLinks) || entityLinks.ValueKind != JsonValueKind.Array)
        {
            return false;
        }

        links = entityLinks.EnumerateArray()
            .Where(item => item.ValueKind == JsonValueKind.Object)
            .Select(item => new AdminRiskEntityLinkDto(
                ReadString(item, "label"),
                ReadString(item, "entityType"),
                ReadString(item, "entityId"),
                ReadString(item, "to")))
            .Where(item => !string.IsNullOrWhiteSpace(item.Label) && !string.IsNullOrWhiteSpace(item.To))
            .ToArray();

        return links.Length > 0;
    }

    private static bool TryGetProperty(JsonElement root, string propertyName, out JsonElement value)
    {
        foreach (var property in root.EnumerateObject())
        {
            if (string.Equals(property.Name, propertyName, StringComparison.OrdinalIgnoreCase))
            {
                value = property.Value;
                return true;
            }
        }

        value = default;
        return false;
    }

    private static string ReadString(JsonElement root, string propertyName)
    {
        if (!TryGetProperty(root, propertyName, out var value))
        {
            return string.Empty;
        }

        return value.ValueKind switch
        {
            JsonValueKind.String => value.GetString() ?? string.Empty,
            JsonValueKind.Number => value.GetRawText(),
            _ => string.Empty,
        };
    }
}
