using System.Text.RegularExpressions; using AVSCartonShipmentVerifier.Configuration; using AVSCartonShipmentVerifier.Data; using Microsoft.Extensions.Options; using MySqlConnector; namespace AVSCartonShipmentVerifier.Repositories; public sealed class CartonVerificationRepository( IVerificationDbConnectionFactory connectionFactory, IOptions options) : ICartonVerificationRepository { private static readonly Regex SqlIdentifierRegex = new("^[A-Za-z_][A-Za-z0-9_]*$", RegexOptions.Compiled); private readonly IVerificationDbConnectionFactory _connectionFactory = connectionFactory; private readonly CartonVerificationOptions _options = options.Value; public async Task GetCartonStatusByUniqueNumberAsync(string uniqueNumber, CancellationToken cancellationToken = default) { await using var connection = _connectionFactory.CreateConnection(); await connection.OpenAsync(cancellationToken); await using var command = connection.CreateCommand(); command.CommandText = $""" SELECT {QuoteIdentifier(_options.MovedToWarehouseColumnName)} FROM {QuoteIdentifier(_options.TableName)} WHERE {QuoteIdentifier(_options.QrColumnName)} = @uniqueNumber LIMIT 1; """; command.Parameters.AddWithValue("@uniqueNumber", uniqueNumber); var result = await command.ExecuteScalarAsync(cancellationToken); if (result is null || result is DBNull) { return CartonVerificationStatus.NotFound; } var moved = Convert.ToInt32(result); return moved != 0 ? CartonVerificationStatus.AlreadyTransferred : CartonVerificationStatus.PendingTransfer; } public async Task MarkShipmentVerifiedAsync(string uniqueNumber, CancellationToken cancellationToken = default) { await using var connection = _connectionFactory.CreateConnection(); await connection.OpenAsync(cancellationToken); await using var command = connection.CreateCommand(); command.CommandText = $""" UPDATE {QuoteIdentifier(_options.TableName)} SET {QuoteIdentifier(_options.MovedToWarehouseColumnName)} = 1 WHERE {QuoteIdentifier(_options.QrColumnName)} = @uniqueNumber AND {QuoteIdentifier(_options.MovedToWarehouseColumnName)} = 0; """; command.Parameters.AddWithValue("@uniqueNumber", uniqueNumber); var affectedRows = await command.ExecuteNonQueryAsync(cancellationToken); return affectedRows > 0; } public async Task GetAvailableCartonCountAsync(CancellationToken cancellationToken = default) { await using var connection = _connectionFactory.CreateConnection(); await connection.OpenAsync(cancellationToken); await using var command = connection.CreateCommand(); command.CommandText = $""" SELECT COUNT(*) FROM {QuoteIdentifier(_options.TableName)} WHERE {QuoteIdentifier(_options.MovedToWarehouseColumnName)} = 0; """; var result = await command.ExecuteScalarAsync(cancellationToken); return Convert.ToInt32(result); } public async Task GetTotalMovedCartonCountAsync(CancellationToken cancellationToken = default) { await using var connection = _connectionFactory.CreateConnection(); await connection.OpenAsync(cancellationToken); await using var command = connection.CreateCommand(); command.CommandText = $""" SELECT COUNT(*) FROM {QuoteIdentifier(_options.TableName)} WHERE {QuoteIdentifier(_options.MovedToWarehouseColumnName)} = 1; """; var result = await command.ExecuteScalarAsync(cancellationToken); return Convert.ToInt32(result); } private static string QuoteIdentifier(string identifier) { if (!SqlIdentifierRegex.IsMatch(identifier)) { throw new InvalidOperationException($"Invalid SQL identifier configured: '{identifier}'."); } return $"`{identifier}`"; } }