using FrameworkDAL.DTO.DirectAction; using FrameworkDAL.Query.DirectAction.DirectActionDetailAdmin; using GB5Shared.DTO.Framework.Login; using GB5Shared.GenerateAutoNumber; using GB5Shared.QueryExecutor; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using static GB5Shared.GB5Constant.Constant; namespace FrameworkDAL.CustomCode.DirectAction.DirectActionDetailAdmin { public class DirectActionDetailAdminDAL : IDirectActionDetailAdminDAL { private readonly IQueryExecutor _qe; private readonly AutoNumber _autoNumber; private readonly ILogger _logger; public DirectActionDetailAdminDAL(IQueryExecutor qe, AutoNumber autoNumber, ILogger logger) { _qe = qe ?? throw new ArgumentNullException(nameof(qe)); _autoNumber = autoNumber ?? throw new ArgumentNullException(nameof(autoNumber)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public async Task> GetDetailListAsync( int directActionId, LoginDTO login, CancellationToken ct = default) { ct.ThrowIfCancellationRequested(); try { _logger.LogInformation("DAL | GetDetailList | Tenant={TenantId} | DirectActionId={Id}", login.ClientId, directActionId); var result = await _qe.QueryAsync( login, DirectActionDetailAdminQB.GET_DETAIL_LIST, new { DirectActionId = directActionId, TenantId = login.ClientId }, cancellationToken: ct).ConfigureAwait(false); return result ?? []; } catch (OperationCanceledException) { _logger.LogWarning("DAL | GetDetailList | Cancelled | DirectActionId={Id}", directActionId); throw; } catch (Exception ex) { _logger.LogError(ex, "DAL | GetDetailList | Error | DirectActionId={Id}", directActionId); throw; } } public async Task GetDetailAsync( int directActionDetailId, LoginDTO login, CancellationToken ct = default) { ct.ThrowIfCancellationRequested(); try { _logger.LogInformation("DAL | GetDetail | Tenant={TenantId} | Id={Id}", login.ClientId, directActionDetailId); return await _qe.QuerySingleAsync( login, DirectActionDetailAdminQB.GET_DETAIL, new { DirectActionDetailId = directActionDetailId, TenantId = login.ClientId }, cancellationToken: ct).ConfigureAwait(false); } catch (OperationCanceledException) { _logger.LogWarning("DAL | GetDetail | Cancelled | Id={Id}", directActionDetailId); throw; } catch (Exception ex) { _logger.LogError(ex, "DAL | GetDetail | Error | Id={Id}", directActionDetailId); throw; } } public async Task InsertDetailAsync( DirectActionDetailAdminDTO dto, LoginDTO login, CancellationToken ct = default) { ct.ThrowIfCancellationRequested(); try { _logger.LogInformation("DAL | InsertDetail | Tenant={TenantId} | ActionCode={Code}", login.ClientId, dto.ActionCode); // DIRECTACTIONDETAILID is a plain INT PK (not IDENTITY) — must be generated here. var auto = await _autoNumber.GetNumberAsync(1, AUTONUMBERCONSTANT.DIRECTACTIONDETAIL, login) .ConfigureAwait(false); var newId = auto.StartNumber; await _qe.ExecuteAsync( login, DirectActionDetailAdminQB.INSERT_DETAIL, new { DirectActionDetailId = newId, dto.DirectActionId, dto.Slno, dto.ActionCode, dto.ActionLabel, dto.EmailPlaceholder, dto.ButtonPayloadPrefix, dto.ApiEndpoint, dto.HttpMethod, dto.PayloadTemplate, dto.NeedsInput, dto.FlowId }, cancellationToken: ct).ConfigureAwait(false); _logger.LogInformation("DAL | InsertDetail | Completed | NewId={NewId}", newId); return newId; } catch (OperationCanceledException) { _logger.LogWarning("DAL | InsertDetail | Cancelled | ActionCode={Code}", dto.ActionCode); throw; } catch (Exception ex) { _logger.LogError(ex, "DAL | InsertDetail | Error | ActionCode={Code}", dto.ActionCode); throw; } } public async Task UpdateDetailAsync( DirectActionDetailAdminDTO dto, LoginDTO login, CancellationToken ct = default) { ct.ThrowIfCancellationRequested(); try { _logger.LogInformation("DAL | UpdateDetail | Tenant={TenantId} | Id={Id}", login.ClientId, dto.DirectActionDetailId); await _qe.ExecuteAsync( login, DirectActionDetailAdminQB.UPDATE_DETAIL, new { dto.DirectActionDetailId, dto.Slno, dto.ActionCode, dto.ActionLabel, dto.EmailPlaceholder, dto.ButtonPayloadPrefix, dto.ApiEndpoint, dto.HttpMethod, dto.PayloadTemplate, dto.NeedsInput, dto.FlowId }, cancellationToken: ct).ConfigureAwait(false); } catch (OperationCanceledException) { _logger.LogWarning("DAL | UpdateDetail | Cancelled | Id={Id}", dto.DirectActionDetailId); throw; } catch (Exception ex) { _logger.LogError(ex, "DAL | UpdateDetail | Error | Id={Id}", dto.DirectActionDetailId); throw; } } public async Task DeleteDetailAsync( int directActionDetailId, LoginDTO login, CancellationToken ct = default) { ct.ThrowIfCancellationRequested(); try { _logger.LogInformation("DAL | DeleteDetail | Tenant={TenantId} | Id={Id}", login.ClientId, directActionDetailId); // Real hard delete — MDIRECTACTIONDETAIL has no STATUS column. await _qe.ExecuteAsync( login, DirectActionDetailAdminQB.DELETE_DETAIL, new { DirectActionDetailId = directActionDetailId }, cancellationToken: ct).ConfigureAwait(false); } catch (OperationCanceledException) { _logger.LogWarning("DAL | DeleteDetail | Cancelled | Id={Id}", directActionDetailId); throw; } catch (Exception ex) { _logger.LogError(ex, "DAL | DeleteDetail | Error | Id={Id}", directActionDetailId); throw; } } public async Task ActionCodeExistsAsync( string actionCode, int excludeDirectActionDetailId, LoginDTO login, CancellationToken ct = default) { ct.ThrowIfCancellationRequested(); var count = await _qe.ExecuteScalarAsync( login, DirectActionDetailAdminQB.EXISTS_ACTIONCODE, new { ActionCode = actionCode, DirectActionDetailId = excludeDirectActionDetailId }, cancellationToken: ct).ConfigureAwait(false); return count == 1; } } }