using GB5Shared.DTO.Framework.Login;
using GB5Shared.Resource.Response;
using Microsoft.Extensions.Logging;
using TCMSBLL.Interfaces;
using TCMSDAL.DTO;
using TCMSDAL.Interfaces;
namespace TCMSBLL.Implementations;
///
/// Business logic for MTCMSTESTCASE + MTCMSTESTSTEP.
/// TC-ID auto-assignment: TC-[ModuleCode]-[SEQ] zero-padded to 3 digits, e.g. TC-INV-001.
/// Steps are fully replaced on every save (delete+insert in DAL transaction).
///
public class TCMSTestCaseBLL : ITCMSTestCaseBLL
{
private readonly ITCMSTestCaseDAL _Dal;
private readonly ITCMSModuleDAL _ModuleDal;
private readonly ILogger _Logger;
public TCMSTestCaseBLL(
ITCMSTestCaseDAL dal,
ITCMSModuleDAL moduleDal,
ILogger logger)
{
_Dal = dal;
_ModuleDal = moduleDal;
_Logger = logger;
}
public async Task GetTestCaseAsync(
int testCaseId, LoginDTO login, CancellationToken ct)
{
var tc = await _Dal.GetTestCaseAsync(testCaseId, login, ct).ConfigureAwait(false);
if (tc is null) return null;
tc.Steps = (await _Dal.GetStepsAsync(testCaseId, login, ct).ConfigureAwait(false)).ToList();
return tc;
}
public async Task> GetTestCaseListAsync(
int moduleId, string? priority, string? testType, string? status, bool? isActive,
LoginDTO login, CancellationToken ct)
=> await _Dal.GetTestCaseListAsync(moduleId, priority, testType, status, isActive, login, ct).ConfigureAwait(false);
public async Task> GetSelectListAsync(
int moduleId, LoginDTO login, CancellationToken ct)
=> await _Dal.GetSelectListAsync(moduleId, login, ct).ConfigureAwait(false);
public async Task SaveTestCaseAsync(
TCMSTestCaseDTO dto, LoginDTO login, CancellationToken ct)
{
try
{
// Validation
if (string.IsNullOrWhiteSpace(dto.Title))
return "Test Case Title is required.";
if (dto.ModuleId == 0)
return "Module is required.";
bool isNew = dto.TestCaseId == 0;
if (isNew)
{
// Auto-assign TC-ID
var module = await _ModuleDal.GetModuleAsync(dto.ModuleId, login, ct).ConfigureAwait(false);
if (module is null) return "Module not found.";
string prefix = $"TC-{module.ModuleCode}";
int seq = await _Dal.GetNextSequenceAsync(prefix, login, ct).ConfigureAwait(false);
dto.TcId = $"{prefix}-{seq:D3}";
int newId = await _Dal.SaveTestCaseAsync(dto, login, ct).ConfigureAwait(false);
if (dto.Steps.Count > 0)
await _Dal.SaveStepsAsync(newId, dto.Steps, login, ct).ConfigureAwait(false);
return $"{SuccessResponse.SaveSuccessMessage} {newId}";
}
else
{
await _Dal.UpdateTestCaseAsync(dto, login, ct).ConfigureAwait(false);
// Always replace steps on update (even if empty — clears old steps)
await _Dal.SaveStepsAsync(dto.TestCaseId, dto.Steps, login, ct).ConfigureAwait(false);
return SuccessResponse.UpdateSuccess;
}
}
catch (Exception ex)
{
_Logger.LogError(ex, "SaveTestCase failed for title {Title}", dto.Title);
throw;
}
}
public async Task DeleteTestCaseAsync(
int testCaseId, LoginDTO login, CancellationToken ct)
{
try
{
await _Dal.DeleteTestCaseAsync(testCaseId, login.UserId, login, ct).ConfigureAwait(false);
return SuccessResponse.DeleteSuccessMessage;
}
catch (Exception ex)
{
_Logger.LogError(ex, "DeleteTestCase failed for id {Id}", testCaseId);
throw;
}
}
}