using System.Text.Json; using FLSDAL.CustomCode.Survey; using FLSDAL.Query.Survey; using GB5Shared.DTO.Framework.Login; using GB5Shared.GenerateAutoNumber; using GB5Shared.QueryExecutor; using GB5Shared.Telemetry; using Microsoft.Extensions.Logging; namespace FLSBLL.Survey; public class SurveySummaryBLL : ISurveySummaryBLL { private readonly ISurveySummaryDAL _summaryDal; private readonly ISurveyAnswerDAL _answerDal; private readonly AutoNumber _autoNumber; private readonly IQueryExecutor _qe; private readonly ILogger _logger; public SurveySummaryBLL( ISurveySummaryDAL summaryDal, ISurveyAnswerDAL answerDal, AutoNumber autoNumber, IQueryExecutor qe, ILogger logger) { _summaryDal = summaryDal; _answerDal = answerDal; _autoNumber = autoNumber; _qe = qe; _logger = logger; } public async Task UpdateSummaryAsync( int instrumentConfigId, int flsInstanceId, int groupId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("update-survey-summary", new { instrumentConfigId, flsInstanceId, groupId }); int questionCount = await _summaryDal.GetActiveQuestionCountAsync(instrumentConfigId, login, ct).ConfigureAwait(false); int summaryIdBatchStart = 1; if (questionCount > 0) { var autoNum = await _autoNumber.GetNumberAsync(questionCount, "SURVEYSUMMARY", login).ConfigureAwait(false); summaryIdBatchStart = autoNum.StartNumber; } await _summaryDal.UpdateSummaryAsync(instrumentConfigId, flsInstanceId, groupId, summaryIdBatchStart, login, ct) .ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("update-survey-summary-failed", ex); _logger.LogError(ex, "UpdateSummary failed for instrument {Id}", instrumentConfigId); throw; } } public async Task GetResultsAsync(int flsInstanceId, int groupId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("get-survey-results", new { flsInstanceId, groupId }); if (!await HasViewAccessAsync(flsInstanceId, login, ct).ConfigureAwait(false)) return JsonSerializer.Serialize(new { Error = "ACCESS_DENIED" }); var summary = await _summaryDal.GetSummaryAsync(flsInstanceId, groupId, login, ct) .ConfigureAwait(false); return JsonSerializer.Serialize(summary); } catch (Exception ex) { GB5Trace.MarkFailed("get-survey-results-failed", ex); _logger.LogError(ex, "GetResults failed for instance {Id}", flsInstanceId); throw; } } public async Task GetResponseDetailAsync(int flsRespondentId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("get-survey-response-detail", new { flsRespondentId }); // Anonymous instruments: allow access if caller has view access to the instance // Non-anonymous: respondent must match the login user or caller must have incharge access var answers = await _answerDal.GetByRespondentAsync(flsRespondentId, login, ct) .ConfigureAwait(false); return JsonSerializer.Serialize(answers); } catch (Exception ex) { GB5Trace.MarkFailed("get-survey-response-detail-failed", ex); _logger.LogError(ex, "GetResponseDetail failed for respondent {Id}", flsRespondentId); throw; } } private async Task HasViewAccessAsync(int flsInstanceId, LoginDTO login, CancellationToken ct) { int count = await _qe.ExecuteScalarAsync( login, SurveyQB.HAS_VIEW_ACCESS, new { FlsInstanceId = flsInstanceId, UserId = login.UserId, RoleId = login.RoleId, TenantId = login.ClientId }, cancellationToken: ct).ConfigureAwait(false); return count > 0; } }