using Microsoft.Data.Sqlite;

namespace ZB.MOM.WW.MxGateway.Server.Security.Authentication;

public sealed class SqliteApiKeyAuditStore(AuthSqliteConnectionFactory connectionFactory) : IApiKeyAuditStore
{
    /// <inheritdoc />
    public async Task AppendAsync(ApiKeyAuditEntry entry, CancellationToken cancellationToken)
    {
        await using SqliteConnection connection = await connectionFactory.OpenConnectionAsync(cancellationToken).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", DateTimeOffset.UtcNow.ToString("O"));
        command.Parameters.AddWithValue("$details", (object?)entry.Details ?? DBNull.Value);

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

    /// <inheritdoc />
    public async Task<IReadOnlyList<ApiKeyAuditRecord>> ListRecentAsync(int count, CancellationToken cancellationToken)
    {
        if (count <= 0)
        {
            return [];
        }

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

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

        List<ApiKeyAuditRecord> records = [];

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

        while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
        {
            records.Add(new ApiKeyAuditRecord(
                AuditId: reader.GetInt64(0),
                KeyId: reader.IsDBNull(1) ? null : reader.GetString(1),
                EventType: reader.GetString(2),
                RemoteAddress: reader.IsDBNull(3) ? null : reader.GetString(3),
                CreatedUtc: DateTimeOffset.Parse(
                    reader.GetString(4),
                    System.Globalization.CultureInfo.InvariantCulture),
                Details: reader.IsDBNull(5) ? null : reader.GetString(5)));
        }

        return records;
    }
}
