using Microsoft.Data.Sqlite;
using ZB.MOM.WW.Auth.Abstractions.ApiKeys;

namespace ZB.MOM.WW.Auth.ApiKeys.Sqlite;

/// <summary>SQLite-backed, append-only audit store for API-key events.</summary>
public sealed class SqliteApiKeyAuditStore(AuthSqliteConnectionFactory connectionFactory) : IApiKeyAuditStore
{
    /// <inheritdoc />
    public async Task AppendAsync(ApiKeyAuditEntry entry, CancellationToken ct)
    {
        ArgumentNullException.ThrowIfNull(entry);

        await using SqliteConnection connection =
            await connectionFactory.OpenConnectionAsync(ct).ConfigureAwait(false);

        await using SqliteCommand command = connection.CreateCommand();
        command.CommandText = """
            INSERT INTO api_key_audit (key_id, event_type, remote_address, created_utc, details)
            VALUES ($key_id, $event_type, $remote_address, $created_utc, $details);
            """;
        command.Parameters.AddWithValue("$key_id", (object?)entry.KeyId ?? DBNull.Value);
        command.Parameters.AddWithValue("$event_type", entry.EventType);
        command.Parameters.AddWithValue("$remote_address", (object?)entry.RemoteAddress ?? DBNull.Value);
        command.Parameters.AddWithValue("$created_utc", entry.CreatedUtc.ToString("O"));
        command.Parameters.AddWithValue("$details", (object?)entry.Details ?? DBNull.Value);

        await command.ExecuteNonQueryAsync(ct).ConfigureAwait(false);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<ApiKeyAuditEntry>> ListRecentAsync(int limit, CancellationToken ct)
    {
        if (limit <= 0)
        {
            return [];
        }

        await using SqliteConnection connection =
            await connectionFactory.OpenConnectionAsync(ct).ConfigureAwait(false);

        await using SqliteCommand command = connection.CreateCommand();
        command.CommandText = """
            SELECT key_id, event_type, remote_address, created_utc, details
            FROM api_key_audit
            ORDER BY audit_id DESC
            LIMIT $limit;
            """;
        command.Parameters.AddWithValue("$limit", limit);

        List<ApiKeyAuditEntry> entries = [];

        await using SqliteDataReader reader = await command.ExecuteReaderAsync(ct).ConfigureAwait(false);

        while (await reader.ReadAsync(ct).ConfigureAwait(false))
        {
            entries.Add(new ApiKeyAuditEntry(
                KeyId: reader.IsDBNull(0) ? null : reader.GetString(0),
                EventType: reader.GetString(1),
                RemoteAddress: reader.IsDBNull(2) ? null : reader.GetString(2),
                CreatedUtc: SqliteValueParsing.ParseUtc(reader.GetString(3)),
                Details: reader.IsDBNull(4) ? null : reader.GetString(4)));
        }

        return entries;
    }
}
