using System.Text.Json;

namespace ClawdDotNet.Core.Deploymentcenter;

/// <summary>Was aus einem Bugtracker-Eintrag geworden ist.</summary>
/// <param name="ItemId">Nummer des Eintrags im Deploymentcenter.</param>
/// <param name="IsNew">False, wenn ein bestehender Eintrag hochgezählt wurde.</param>
/// <param name="OccurrenceCount">Wie oft dieses Vorkommnis bisher gezählt wurde.</param>
/// <param name="Url">Adresse der Übersicht, für einen Hinweis an den Benutzer.</param>
public sealed record BugtrackerReport(long ItemId, bool IsNew, int OccurrenceCount, string? Url);

/// <summary>Art eines Eintrags. Der Server kennt darüber hinaus noch <c>idea</c>.</summary>
public static class BugtrackerItemType
{
    public const string Bug = "bug";
    public const string Feature = "feature";
    public const string Idea = "idea";
}

/// <summary>
/// Anbindung an <c>POST /api/bugtracker/v1/report</c> — der Weg, auf dem ClawdDotNet
/// selbst (oder ein Benutzer über die Oberfläche) einen Fehler oder Wunsch einträgt.
///
/// <para>Abgegrenzt vom <see cref="ErrorReporter"/>: Der meldet <em>ungefangene</em>
/// Ausnahmen automatisch; hier geht es um bewusst formulierte Einträge mit Titel und
/// Beschreibung. Serverseitig landen beide in derselben Tabelle — was richtig ist,
/// denn ein zweiter Speicher wäre nur ein zweiter Ort, an dem man suchen müsste.</para>
///
/// <para><b>Der Absender kommt aus dem Token</b> und lässt sich nicht frei wählen —
/// sonst könnte sich ein Agent als ein anderer ausgeben.</para>
/// </summary>
public sealed class BugtrackerClient(
    DeploymentcenterApi api, string projectSlug, string environment, string build)
{
    /// <param name="type">Siehe <see cref="BugtrackerItemType"/>.</param>
    /// <param name="clientRef">
    /// Freier Idempotenz-Schlüssel. Zweimal derselbe Wert erzeugt keinen zweiten
    /// Eintrag — nützlich, wenn eine Meldung nach einem Verbindungsabbruch wiederholt
    /// wird.
    /// </param>
    public async Task<BugtrackerReport> ReportAsync(
        string type,
        string title,
        string? description = null,
        string severity = "medium",
        string? clientRef = null,
        IReadOnlyDictionary<string, object?>? context = null,
        CancellationToken ct = default)
    {
        var payload = new Dictionary<string, object?>
        {
            ["project_slug"] = projectSlug,
            ["type"] = type,
            ["title"] = title,
            ["description"] = description,
            ["severity"] = severity,
            ["environment"] = environment,
            ["build_version"] = build
        };

        if (!string.IsNullOrWhiteSpace(clientRef))
            payload["client_ref"] = clientRef;

        if (context is { Count: > 0 })
            payload["context"] = context;

        var response = await api.PostAsync("/api/bugtracker/v1/report", payload, ct)
            .ConfigureAwait(false);

        return new BugtrackerReport(
            ReadLong(response, "item_id"),
            ReadBool(response, "is_new"),
            (int)ReadLong(response, "occurrence_count"),
            ReadString(response, "url"));
    }

    private static long ReadLong(JsonElement root, string name) =>
        root.TryGetProperty(name, out var v) && v.ValueKind == JsonValueKind.Number
            ? v.GetInt64()
            : 0;

    private static bool ReadBool(JsonElement root, string name) =>
        root.TryGetProperty(name, out var v) && v.ValueKind == JsonValueKind.True;

    private static string? ReadString(JsonElement root, string name) =>
        root.TryGetProperty(name, out var v) && v.ValueKind == JsonValueKind.String
            ? v.GetString()
            : null;
}
