using EnablementDAL.CustomCode.ShowSchedule; using EnablementDAL.DTO; using EnablementDAL.Implementations; using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Enum; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Framework.ResponseStandard; using GB5Shared.EventLogPublish; using GB5Shared.GB5Exception; using GB5Shared.GenerateAutoNumber; using GB5Shared.Resource.Response; using Microsoft.Extensions.Logging; using System.Text.Json; using System.Text.RegularExpressions; namespace EnablementBLL.ShowSchedule; public class ShowScheduleBLL : IShowScheduleBLL { public const byte ONCE = 0; public const byte DAILY = 1; public const byte WEEKLY = 2; public const byte MONTHLY = 3; public const byte ON_LOGIN = 4; public const byte ON_FIRST_LOGIN = 5; private const byte STANDALONE = 0; private const byte COMBINED = 1; private static readonly Regex TimePattern = new(@"^([01]\d|2[0-3]):[0-5]\d$", RegexOptions.Compiled); private readonly IShowScheduleDAL _dal; private readonly AutoNumber _autoNumber; private readonly EventLogPublish _eventLog; private readonly ILogger? _logger; public ShowScheduleBLL( IShowScheduleDAL dal, AutoNumber autoNumber, EventLogPublish eventLog, ILogger? logger = null) { _dal = dal; _autoNumber = autoNumber; _eventLog = eventLog; _logger = logger; } // ------------------------------------------------------------------------- // Admin CRUD (author-time) — separate from the resolver's own read path // (ShowResolverQB.GET_SHOW_SCHEDULES), which is untouched by this file. // A Show may have zero or one schedule row, so Save behaves as an upsert // keyed by ShowId rather than by ShowScheduleId. // ------------------------------------------------------------------------- public async Task> GetShowScheduleAsync(int showId, LoginDTO login, CancellationToken ct) { if (showId <= 0) throw new ArgumentException("ShowId must be greater than zero."); var dto = await _dal.GetShowScheduleAsync(showId, login, ct).ConfigureAwait(false); if (dto is null) throw new NotFoundException($"ShowSchedule for Show {showId} not found."); return OkResponse(dto); } public async Task> SaveShowScheduleAsync(ShowScheduleDTO dto, LoginDTO login, CancellationToken ct) { if (dto.ShowId <= 0) throw new ArgumentException("ShowId must be greater than zero."); if (dto.ScheduleType > ON_FIRST_LOGIN) throw new ArgumentException("ScheduleType must be in range 0-5."); if (dto.ScheduleMode > COMBINED) throw new ArgumentException("ScheduleMode must be in range 0-1."); if (dto.StartDate.HasValue && dto.EndDate.HasValue && dto.StartDate > dto.EndDate) throw new ArgumentException("StartDate must not be later than EndDate."); if (string.IsNullOrWhiteSpace(dto.ScheduleTime) || !TimePattern.IsMatch(dto.ScheduleTime)) throw new ArgumentException("ScheduleTime must be in HH:mm format."); if (dto.ScheduleType is WEEKLY or MONTHLY && string.IsNullOrWhiteSpace(dto.RecurrenceJson)) throw new ArgumentException("RecurrenceJson is required for Weekly/Monthly schedules."); if (!string.IsNullOrWhiteSpace(dto.RecurrenceJson)) { try { using var _ = JsonDocument.Parse(dto.RecurrenceJson); } catch (JsonException) { throw new ArgumentException("RecurrenceJson must be valid JSON."); } } var existing = await _dal.GetShowScheduleAsync(dto.ShowId, login, ct).ConfigureAwait(false); dto.TenantId = login.ClientId; dto.ModifiedById = login.UserId; bool isNew = existing is null; if (isNew) { var an = await _autoNumber.GetNumberAsync(1, "SHOWSCHEDULE", login).ConfigureAwait(false); dto.ShowScheduleId = an.StartNumber; dto.CreatedById = login.UserId; dto.SourceType = login.SourceType; await _dal.InsertShowScheduleAsync(dto, login, ct).ConfigureAwait(false); _ = _eventLog.PublishEventLogAsync("ShowSchedule Created", dto, 1, dto.ShowScheduleId, login, ct: ct); } else { dto.ShowScheduleId = existing!.ShowScheduleId; await _dal.UpdateShowScheduleAsync(dto, login, ct).ConfigureAwait(false); _ = _eventLog.PublishEventLogAsync("ShowSchedule Updated", dto, 1, dto.ShowScheduleId, login, ct: ct); } _logger?.LogInformation("ShowSchedule saved ShowScheduleId={ShowScheduleId} ShowId={ShowId}", dto.ShowScheduleId, dto.ShowId); return OkResponse(isNew ? $"{SuccessResponse.SaveSuccessMessage} {dto.ShowScheduleId}" : SuccessResponse.UpdateSuccess); } public async Task> DeleteShowScheduleAsync(int showScheduleId, LoginDTO login, CancellationToken ct) { if (showScheduleId <= 0) throw new ArgumentException("ShowScheduleId must be greater than zero."); await _dal.DeleteShowScheduleAsync(showScheduleId, login, ct).ConfigureAwait(false); _ = _eventLog.PublishEventLogAsync("ShowSchedule Deleted", new { ShowScheduleId = showScheduleId }, 1, showScheduleId, login, ct: ct); return OkResponse(SuccessResponse.DeleteSuccessMessage); } private static ResponseStandardDTO OkResponse(object body) => new() { Body = body, Status = FrameworkEnumDTO.ResponseStatus.Ok }; public async Task GetSelectListShowSchedule( int FirstNumber, int MaxResult, CriteriaDTO CriteriaDTO, LoginDTO LoginDTO) { try { return await _dal.GetSelectListShowSchedule( FirstNumber, MaxResult, CriteriaDTO, LoginDTO); } catch (Exception) { throw; } } public async Task GetShowScheduleList( CriteriaDTO CriteriaDTO, LoginDTO LoginDTO) { try { return await _dal.GetShowScheduleList( CriteriaDTO, LoginDTO); } catch (Exception) { throw; } } }