using System.Text;
using System.Text.Json;

namespace ZB.MOM.WW.ScadaBridge.CLI.Commands;

/// <summary>
/// Arguments for an <c>audit backfill-source-node</c> invocation.
/// </summary>
public sealed class AuditBackfillSourceNodeArgs
{
    /// <summary>
    /// Value written into <c>SourceNode</c> for NULL rows (default <c>"unknown"</c>).
    /// </summary>
    public string Sentinel { get; set; } = "unknown";

    /// <summary>
    /// Only rows with <c>OccurredAtUtc</c> strictly before this UTC datetime are
    /// eligible. Required — must be an ISO-8601 UTC datetime.
    /// </summary>
    public string Before { get; set; } = string.Empty;

    /// <summary>
    /// Maximum rows updated per batch (default 5000). Caps the per-transaction
    /// log footprint; the loop repeats until no rows remain.
    /// </summary>
    public int BatchSize { get; set; } = 5000;
}

/// <summary>
/// Pure helpers for the <c>audit backfill-source-node</c> subcommand. Builds
/// the request body, POSTs to
/// <c>/api/audit/backfill-source-node</c>, and renders the result. Kept separate
/// from the command wiring so each piece is unit-testable without standing up the
/// command tree.
/// </summary>
public static class AuditBackfillHelpers
{
    private static readonly JsonSerializerOptions JsonWriteOptions = new()
    {
        WriteIndented = true,
    };

    /// <summary>
    /// Builds the JSON request body for <c>POST /api/audit/backfill-source-node</c>.
    /// </summary>
    /// <param name="args">The backfill arguments.</param>
    /// <returns>A JSON string suitable for the request body.</returns>
    public static string BuildRequestBody(AuditBackfillSourceNodeArgs args)
    {
        var obj = new
        {
            sentinel = args.Sentinel,
            before = args.Before,
            batchSize = args.BatchSize,
        };
        return JsonSerializer.Serialize(obj);
    }

    /// <summary>
    /// Executes the backfill: POSTs <c>/api/audit/backfill-source-node</c> and
    /// prints the result. Returns the process exit code (0 = success,
    /// 1 = error, 2 = authorization failure).
    /// </summary>
    /// <param name="client">The management HTTP client.</param>
    /// <param name="args">The backfill arguments.</param>
    /// <param name="output">The output writer for results.</param>
    /// <returns>A task that resolves to the process exit code.</returns>
    public static async Task<int> RunBackfillAsync(
        ManagementHttpClient client,
        AuditBackfillSourceNodeArgs args,
        TextWriter output)
    {
        var body = BuildRequestBody(args);
        var response = await client.SendPostAsync(
            "api/audit/backfill-source-node", body, TimeSpan.FromMinutes(10));

        if (response.JsonData == null)
        {
            OutputFormatter.WriteError(
                response.Error ?? "Backfill request failed.", response.ErrorCode ?? "ERROR");
            return CommandHelpers.IsAuthorizationFailure(response) ? 2 : 1;
        }

        // Parse and display the result.
        try
        {
            using var doc = JsonDocument.Parse(response.JsonData);
            var root = doc.RootElement;
            var rowsUpdated = root.TryGetProperty("rowsUpdated", out var r)
                ? r.GetInt64()
                : 0L;
            var sentinel = root.TryGetProperty("sentinel", out var s)
                ? s.GetString() ?? args.Sentinel
                : args.Sentinel;
            var before = root.TryGetProperty("before", out var b)
                ? b.GetString() ?? args.Before
                : args.Before;

            output.WriteLine($"SourceNode backfill complete.");
            output.WriteLine($"  rows updated : {rowsUpdated}");
            output.WriteLine($"  sentinel     : {sentinel}");
            output.WriteLine($"  before       : {before}");
        }
        catch (JsonException)
        {
            // Server returned success but non-JSON body — not expected; print raw.
            output.WriteLine(response.JsonData);
        }

        output.Flush();
        return 0;
    }
}
