using FluentValidation;
using IWS5.Core.DTO;
using IWS5.Core.Enums;
using IWS5.Core.EventTrigger;
using IWS5.Core.Exceptions;
using IWS5.Core.Models;
using IWS5.Core.Models.Request;
using IWS5.Core.Models.TriggerAction;
using IWS5.Core.Services;
using IWS5.DatabaseAccess.Interfaces;
using IWS5.DatabaseAccess.IwsDataModels;
using IWS5.Services.EventTrigger;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Serilog;
using System.Globalization;

namespace IWS5.Services;

public class WorkItemService(
    IWorkItemReferenceRepository workItemReferenceRepository,
    IRightsRepository rightsRepository,
    IProcessRepository processRepository,
    IQueueRepository queueRepository,
    IButtonRepository buttonRepository,
    IDocumentCabinetDefinitionRepository documentCabinetDefinitionRepository,
    IEventDefinitionRepository eventDefinitionRepository,
    IFieldDefinitionRepository fieldDefinitionRepository,
    ITriggerDefinitionRepository triggerDefinitionRepository,
    IValidator<CreateWorkItemRequest> createWorkItemRequestValidator,
    IPendingWorkItemReferenceRepository pendingWorkItemReferenceRepository,
    IServiceProvider _serviceProvider,
    ILogger logger) : IWorkItemService
{
    public async Task<CodeResponse<List<WorkItemListItemDTO>>> ListWorkItems(WorkItemByQueueRequest workItemByQueueRequest)
    {
        if (workItemByQueueRequest.QueueId == 0)
        {
            logger.Error("Queue {workItemRequest.QueueId} is required for List work items or should be more then 0",
                workItemByQueueRequest.QueueId);
            return new CodeResponse<List<WorkItemListItemDTO>>(ResponseCode.BadRequest, "Queue ID is required");
        }

        logger.Information("Starting ListWorkItems for User {UserName} and queue {queueId}", workItemByQueueRequest.UserName,
            workItemByQueueRequest.QueueId);

        var workItemReferences = await workItemReferenceRepository.GetAllowedWorkItems(workItemByQueueRequest);
        var workItemIds = workItemReferences.Select(wiReference => wiReference.WorkItem.WorkItemId).ToArray();
        var fieldDefinitions = await fieldDefinitionRepository.ListFieldDefinitionsAndInstancesByWorkItemIdAndQueueIdAsync(workItemIds, workItemByQueueRequest.QueueId, workItemByQueueRequest.UserName);
        
        if (workItemReferences == null || !workItemReferences.Any())
        {
            logger.Error("No work item was found using queue ID {queueId} as parameter", workItemByQueueRequest.QueueId);
            return new CodeResponse<List<WorkItemListItemDTO>>(ResponseCode.OK, $"No work item was found using queue ID {workItemByQueueRequest.QueueId} as parameter");
        }

        var mappedItems = new List<WorkItemListItemDTO>(workItemReferences.Count);
        foreach (var workItemReference in workItemReferences)
        {
            var dto = MapAtWorkItemReferenceDTO(workItemReference, fieldDefinitions);
            mappedItems.Add(dto);
        }

        logger.Information("Successfully retrieved {Count} work items for User {UserName}", mappedItems.Count, workItemByQueueRequest.UserName);
        
        return new CodeResponse<List<WorkItemListItemDTO>>(ResponseCode.OK, string.Empty, mappedItems);
    }

    public async Task<CodeResponse<List<WorkItemInboxListItemDto>>> ListWorkItems(BaseRequest request)
    {
        if (request == null)
        {
            logger.Error("ListWorkItems inbox method called with null request");
            return new CodeResponse<List<WorkItemInboxListItemDto>>(ResponseCode.BadRequest, "Request cannot be null");
        }

        if (string.IsNullOrEmpty(request.UserName))
        {
            logger.Error("ListWorkItems inbox method called with empty username");
            return new CodeResponse<List<WorkItemInboxListItemDto>>(ResponseCode.BadRequest, "Username is required");
        }

        logger.Information("Starting ListWorkItems inbox for user {UserName}", request.UserName);

        try
        {
            var data = await workItemReferenceRepository.GetInboxWorkItems(request);

            if (data == null || !data.Any())
            {
                logger.Warning("No inbox work items found for user {UserName}", request.UserName);
                return new CodeResponse<List<WorkItemInboxListItemDto>>(ResponseCode.OK, $"No inbox work items found for user {request.UserName}");
            }

            var dtos = data.Select(item => new WorkItemInboxListItemDto
            {
                WorkItemReferenceId = item.WorkItemReferenceId,
                WorkItemId = item.WorkItemId,
                LockedBy = item.WorkItem.LockedBy,
                ProcessId = item.WorkItem.ProcessId,
                ProcessName = $"{item.WorkItem.Process.ProcessName} v{item.WorkItem.Process.ProcessVersion}",
                QueueId = item.QueueId,
                QueueName = item.Queue.Queue,
                Description = item.WorkItem.WorkItemName,
                Created = item.WorkItem.Created,
                Creator = item.WorkItem.Creator,
                SentBy = item.LastAction,
                AssignedTo = item.AssignedTo
            }).ToList();

            logger.Information("Successfully retrieved {Count} inbox work items for user {UserName}", dtos.Count, request.UserName);
            return new CodeResponse<List<WorkItemInboxListItemDto>>(ResponseCode.OK, "", dtos);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "Error retrieving inbox work items for user {UserName}", request.UserName);
            return new CodeResponse<List<WorkItemInboxListItemDto>>(ResponseCode.InternalServerError,
                $"An error occurred while retrieving inbox work items: {ex.Message}");
        }
    }

    public async Task<Response<WorkItemListItemDTO>> CreateWorkItemAsync(CreateWorkItemRequest createWorkItemRequest,
        string userName)
    {
        await createWorkItemRequestValidator.ValidateAndThrowAsync(createWorkItemRequest);

        var process = await processRepository.FindAsync(
            p => p.ProcessId == createWorkItemRequest.ProcessId,
            p => p.AtfieldDefinitions);

        var createProcessRight = await rightsRepository.ListUserRelatedRights(userName, ObjectType.Process,
            ATRightAllowRight.CreateWorkitem, process.ObjectId);

        if (createProcessRight.Count == 0)
        {
            logger.Error("User {UserName} is not allowed to add workitem", userName);
            throw new ForbiddenAccessException($"User {userName} is not allowed to add workitem");
        }

        var attachDocumentRight = await rightsRepository.ListUserRelatedRights(userName, ObjectType.Process,
            ATRightAllowRight.AttachDocument, process.ObjectId);

        if (attachDocumentRight.Count == 0 && createWorkItemRequest.Documents.Any())
        {
            logger.Error("User {UserName} is not allowed to attach document", userName);
            throw new ForbiddenAccessException($"User {userName} is not allowed to add workitem");
        }

        var fieldIds = createWorkItemRequest.FolderFields.Select(f => f.FolderFieldId).ToArray();
        if (fieldIds.Length > 0)
        {
            var fieldObjectIds = process.AtfieldDefinitions
                .Where(f => fieldIds.Contains(f.FieldId))
                .Select(field => field.ObjectId).ToArray();

            var editFolderFieldRights = await rightsRepository.ListUserRelatedRights(userName, ObjectType.FolderField,
                ATRightAllowRight.EditFolderField, fieldObjectIds);
            var allowedToEditFieldIds = editFolderFieldRights.Select(right => right.ObjectGuid).ToArray();

            var allFieldsAllowed = fieldObjectIds.All(id => allowedToEditFieldIds.Contains(id));
            if (!allFieldsAllowed)
            {
                logger.Error("User {UserName} is not allowed to edit folder fields", userName);
                throw new ForbiddenAccessException($"User {userName} is not allowed to edit folder fields");
            }
        }

        var documentTemplateFieldNames =
            createWorkItemRequest.Documents.SelectMany(d => d.DocumentFields).Select(f => f.FieldName).ToArray();
        if (documentTemplateFieldNames.Length > 0)
        {
            var documentTemplateFields =
                await documentCabinetDefinitionRepository.ListAsync(documentDef =>
                    documentTemplateFieldNames.Contains(documentDef.FieldName));
            var documentTemplateFieldObjectIds = documentTemplateFields.Select(f => f.ObjectId).ToArray();

            var editDocumentFieldRights = await rightsRepository.ListUserRelatedRights(userName, ObjectType.DocumentField,
                ATRightAllowRight.EditDocField, documentTemplateFieldObjectIds);
            var allowedToEditDocumentFieldIds = editDocumentFieldRights.Select(right => right.ObjectGuid).ToArray();
            var allFieldsAllowed = documentTemplateFieldObjectIds.All(id => allowedToEditDocumentFieldIds.Contains(id));
            if (!allFieldsAllowed)
            {
                logger.Error("User {UserName} is not allowed to edit folder fields", userName);
                throw new ForbiddenAccessException($"User {userName} is not allowed to edit folder fields");
            }
        }

        var addedWorkItemReference = await workItemReferenceRepository.CreateWorkItemAsync(createWorkItemRequest, userName);
        var dto = MapAtWorkItemReferenceDTO(addedWorkItemReference);
        return new Response<WorkItemListItemDTO>(dto, true);
    }

    public async Task<CodeResponse<WorkItemListItemDTO>> CloneWorkItemAsync(CloneWorkItemRequest cloneWorkItemRequest, string userName)
    {
        var workItemReference = await workItemReferenceRepository.FindAsync(wir => wir.WorkItemReferenceId == cloneWorkItemRequest.WorkItemReferenceId, wir => wir.WorkItem);
        if (workItemReference == null)
        {
            logger.Error("Work item with WorkItemReferenceId {WorkItemReferenceId} not found.", cloneWorkItemRequest.WorkItemReferenceId);
            return new CodeResponse<WorkItemListItemDTO>(ResponseCode.BadRequest, $"Work item with WorkItemReferenceId {cloneWorkItemRequest.WorkItemReferenceId} not found.");
        }

        var process = await processRepository.FindAsync(p => p.ProcessId == workItemReference.WorkItem.ProcessId);

        var cloneWorkItemsRight = await rightsRepository.ListUserRelatedRights(userName, ObjectType.Process, ATRightAllowRight.CloneWorkitems, process.ObjectId);
        if (cloneWorkItemsRight.Count == 0)
        {
            logger.Error("User {UserName} is not allowed to clone work items in process with ProcessId {ProcessId}.", userName, process.ProcessId);
            return new CodeResponse<WorkItemListItemDTO>(ResponseCode.Forbidden, $"User {userName} is not allowed to clone work items in process with ProcessId {process.ProcessId}.");
        }

        var result = await workItemReferenceRepository.CloneWorkItemAsync(cloneWorkItemRequest, userName, workItemReference);
        var response = MapAtWorkItemReferenceDTO(result);
        return new CodeResponse<WorkItemListItemDTO>(ResponseCode.OK, null, response);
    }

    public async Task<Response<string>> LockWorkItemAsync(int workItemReferenceId, string userName)
    {
        try
        {
            var workItem = await workItemReferenceRepository
                .FindAsync(wir =>  wir.WorkItemReferenceId == workItemReferenceId, 
                wir => wir.WorkItem);
            
            var result = await workItemReferenceRepository.LockWorkItem(workItem.WorkItemId, userName);

            if (string.IsNullOrEmpty(result))
            {
                throw new InvalidOperationException("Failed to lock the work item, workItemId does not exist.");
            }

            var triggerDefinitions = await triggerDefinitionRepository.ListTriggerDefinitionsByWorkItemIdAsync(workItem.WorkItemId, ATTriggerHook.OnOpenWorkItem);
            foreach (var triggerDefinition in triggerDefinitions.Where(trigger => (ATTriggerAction)trigger.ActionId != ATTriggerAction.SendToEvent && 
                                                                                  (ATTriggerAction)trigger.ActionId != ATTriggerAction.SendToProcess))
            {
                var processor =
                    _serviceProvider.GetKeyedService<ITriggerProcessor>(
                        (ATTriggerAction)triggerDefinition.ActionId);

                if (processor is EmailTriggerProcessor emailTriggerProcessor)
                {
                    await emailTriggerProcessor.ProcessTrigger(triggerDefinition.TriggerAction, workItem.WorkItemId, workItem.SourceUser?.ToString(), workItem.SourceQueueId, workItem.EventId, workItem.LastAction?.ToString());
                } else
                {
                    await processor?.ProcessTrigger(triggerDefinition.TriggerAction, workItem.WorkItemId);
                }
            }
            
            return new Response<String>(result, true, null);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "An error occurred while locking work item {WorkItemId} by user {UserName}.",
                workItemReferenceId, userName);
            throw;
        }
    }

    public async Task<Response<String>> UnlockWorkItemAsync(int workItemReferenceId)
    {
        try
        {
            var result = await workItemReferenceRepository.UnlockWorkItem(workItemReferenceId);

            if (string.IsNullOrEmpty(result))
            {
                throw new InvalidOperationException("Failed to unlock the work item, workItemId does not exist.");
            }

            var workItemReference = await workItemReferenceRepository.FindAsync(wir => wir.WorkItemReferenceId == workItemReferenceId);

            var triggerDefinitions = await triggerDefinitionRepository.ListTriggerDefinitionsByWorkItemIdAsync(workItemReference.WorkItemId);
            foreach (var triggerDefinition in triggerDefinitions)
            {
                var processor = _serviceProvider.GetKeyedService<ITriggerProcessor>((ATTriggerAction)triggerDefinition.ActionId);

                if (processor is EmailTriggerProcessor emailTriggerProcessor)
                {
                    await emailTriggerProcessor.ProcessTrigger(triggerDefinition.TriggerAction, workItemReference.WorkItemId, workItemReference.SourceUser?.ToString(), workItemReference.SourceQueueId, workItemReference.EventId, workItemReference.LastAction?.ToString());
                }
                else
                {
                    await processor?.ProcessTrigger(triggerDefinition.TriggerAction, workItemReference.WorkItemId);
                }
            }

            return new Response<String>(result, true, null);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "An error occurred while unlocking work item {WorkItemId}.", workItemReferenceId);
            throw;
        }
    }

    public async Task<bool> IsLockedForUserByWorkItemReferenceId(int workItemReferenceId, string userName)
    {
        try
        {
            var result = await workItemReferenceRepository.IsLockedForUserByWorkItemReferenceId(workItemReferenceId, userName);

            return result;
        }
        catch (NotFoundException ex)
        {
            logger.Warning(ex, "Invalid work item reference ID {WorkItemId}.", workItemReferenceId);
            throw;
        }
        catch (Exception ex)
        {
            logger.Error(ex, "An error occurred while checking if work item {WorkItemId} is locked by user {UserName}.",
                workItemReferenceId, userName);
            throw;
        }
    }

    public async Task<CodeResponse<WorkItemListItemDTO>> ForwardWorkItemAsync(ForwardWorkItemRequest forwardWorkItemRequest, string userName)
    {
        var queue = await queueRepository.FindAsync(q => q.Id == forwardWorkItemRequest.RelatedQueueId);
        var clickedFromEvent = await eventDefinitionRepository
            .FindAsync(atEvent => atEvent.EventId == queue.EventId 
                                  && (atEvent.EventTypeId == (int)ATEventType.User || atEvent.EventTypeId == (int)ATEventType.Queue));

        var workItemReference = await workItemReferenceRepository.FindAsync(wir => wir.WorkItemReferenceId == forwardWorkItemRequest.WorkItemReferenceId);

        switch (clickedFromEvent.EventTypeId)
        {
            case (int)ATEventType.User:
            {
                if (string.IsNullOrEmpty(workItemReference.AssignedTo) || workItemReference.AssignedTo.ToLower() != userName.ToLower())
                {
                    logger.Error("User {UserName} is not assigned to work item {WorkItemReferenceId}", userName, forwardWorkItemRequest.WorkItemReferenceId);
                    return new CodeResponse<WorkItemListItemDTO>(ResponseCode.Unauthorized, $"User {userName} is not assigned to work item {forwardWorkItemRequest.WorkItemReferenceId}");
                }
                break;
            }
            case (int)ATEventType.Queue:
            {
                var buttonClicked = await buttonRepository.FindAsync(button => button.ButtonName == forwardWorkItemRequest.ActionFromDropDown && button.Queue.Id == forwardWorkItemRequest.RelatedQueueId);
                var rights = await rightsRepository.ListUserRelatedRights(userName, ObjectType.Button, ATRightAllowRight.ClickButton, buttonClicked.ObjectId);
        
                if (rights.Count == 0)
                {
                    logger.Error("User {UserName} is not allowed to click button {ButtonName}", userName,
                        forwardWorkItemRequest.ActionFromDropDown);
                    return new CodeResponse<WorkItemListItemDTO>(ResponseCode.Forbidden,
                        $"User {userName} is not allowed to click button {forwardWorkItemRequest.ActionFromDropDown}");
                }

                break;
            }
        }

        var triggerDefinitions = await triggerDefinitionRepository.ListTriggerDefinitionsByWorkItemIdAsync(workItemReference.WorkItemId, ATTriggerHook.OnForwardWorkItem);
        foreach (var triggerDefinition in triggerDefinitions)
        {
            var triggerAction = (ATTriggerAction)triggerDefinition.ActionId;
            var processor = _serviceProvider.GetKeyedService<ITriggerProcessor>(triggerAction);

            bool triggerProcessed = false;
            if (processor is EmailTriggerProcessor emailTriggerProcessor)
            {
                triggerProcessed = await emailTriggerProcessor.ProcessTrigger(triggerDefinition.TriggerAction, workItemReference.WorkItemId, workItemReference.SourceUser?.ToString(), workItemReference.SourceQueueId, workItemReference.EventId, workItemReference.LastAction?.ToString());
            }
            else
            {
                triggerProcessed = await processor?.ProcessTrigger(triggerDefinition.TriggerAction, workItemReference.WorkItemId);
            }

            if (triggerProcessed && (triggerAction == ATTriggerAction.SendToEvent || triggerAction == ATTriggerAction.SendToProcess))
            {
                workItemReference = await workItemReferenceRepository.FindAsync(wir => wir.WorkItemReferenceId == forwardWorkItemRequest.WorkItemReferenceId, wir => wir.WorkItem);
                var dto = MapAtWorkItemReferenceDTO(workItemReference);

                return new CodeResponse<WorkItemListItemDTO>(ResponseCode.OK, null, dto);
            }
        }

        var forwardFromQueue = await workItemReferenceRepository.ForwardWorkItemAsync(forwardWorkItemRequest, userName);
        await pendingWorkItemReferenceRepository.DeleteByWorkItemReferenceIdAsync(forwardWorkItemRequest.WorkItemReferenceId);
        var forwardFromQueueDto = MapAtWorkItemReferenceDTO(forwardFromQueue);
        
        return new CodeResponse<WorkItemListItemDTO>(ResponseCode.OK, message:null, forwardFromQueueDto);
    }

    public async Task<Response<String>> RenameWorkItemAsync(string newName, int workitemRefId)
    {
        try
        {
            var workItemRef = await workItemReferenceRepository.FindAsync(
                wReference => wReference.WorkItemReferenceId == workitemRefId,
                wRef => wRef.WorkItem);
            workItemRef.WorkItem.WorkItemName = newName;
            await workItemReferenceRepository.UpdateAsync(workItemRef);
            return new Response<string>(workItemRef.WorkItem.WorkItemName, true, null);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "An error occurred while renaming work item {WorkItemId}.", workitemRefId);
            throw;
        }
    }

    private static WorkItemListItemDTO MapAtWorkItemReferenceDTO(
        AtworkItemReference workItemReference, 
        List<AtfieldDefinition> fieldDefinitions)
    {
        var newWorkItemListItemDTO = new WorkItemListItemDTO
        {
            WorkItemReferenceId = workItemReference.WorkItemReferenceId,
            WorkItemId = workItemReference.WorkItem.WorkItemId,
            QueueId = workItemReference.QueueId,
            QueueName = (workItemReference.Queue?.Queue ?? null) ?? string.Empty,
            LockedBy = workItemReference.WorkItem.LockedBy,
            Description = workItemReference.WorkItem.WorkItemName,
            Created = workItemReference.WorkItem.Created,
            Creator = workItemReference.WorkItem.Creator,
            SentBy = workItemReference.LastAction,
            AssignedTo = workItemReference.AssignedTo ?? string.Empty,
            SignedBy = workItemReference.WorkItem.Atdocuments?.FirstOrDefault()?.SignedBy ?? string.Empty
        };
        
        newWorkItemListItemDTO.FieldList = fieldDefinitions.Select(fDefinition =>
        {
            var fieldInstanceId = fDefinition.DataType switch
            {
                (int)FieldInstanceType.Date => fDefinition.AtfieldInstanceDates.FirstOrDefault(fid => fid.WorkItemId == workItemReference.WorkItem.WorkItemId)
                    ?.FieldInstanceId,
                (int)FieldInstanceType.Number => fDefinition.AtfieldInstanceNumbers.FirstOrDefault(fin => fin.WorkItemId == workItemReference.WorkItem.WorkItemId)
                    ?.FieldInstanceId,
                (int)FieldInstanceType.String => fDefinition.AtfieldInstanceStrings.FirstOrDefault(fid => fid.WorkItemId == workItemReference.WorkItem.WorkItemId)
                    ?.FieldInstanceId,
                (int)FieldInstanceType.Option => fDefinition.AtfieldInstanceOptions.FirstOrDefault(fid => fid.WorkItemId == workItemReference.WorkItem.WorkItemId)
                    ?.FieldInstanceId,
                _ => null
            };

            var fieldInstanceValue = fDefinition.DataType switch
            {
                (int)FieldInstanceType.Date => fDefinition.AtfieldInstanceDates.FirstOrDefault(fis => fis.WorkItemId == workItemReference.WorkItem.WorkItemId)?.FieldValue
                    .ToString(),
                (int)FieldInstanceType.Number => fDefinition.AtfieldInstanceNumbers.FirstOrDefault(fin => fin.WorkItemId == workItemReference.WorkItem.WorkItemId)?.FieldValue
                    .ToString(),
                (int)FieldInstanceType.String => fDefinition.AtfieldInstanceStrings.FirstOrDefault(fid => fid.WorkItemId == workItemReference.WorkItem.WorkItemId)?.FieldValue
                    .ToString(),
                (int)FieldInstanceType.Option => fDefinition.AtfieldInstanceOptions.FirstOrDefault(fid => fid.WorkItemId == workItemReference.WorkItem.WorkItemId)?.FieldValue
                    .ToString(),
                _ => null
            };
            
            var workItemFieldListDTO = new WorkItemFieldListDTO
            {
                FieldId = fDefinition.FieldId,
                FieldInstanceId = fieldInstanceId,
                FieldProcessId = fDefinition.ProcessId,
                DataType = fDefinition.DataType,
                FieldName = fDefinition.FieldName,
                FieldValue = fieldInstanceValue ?? (fDefinition.DataType != (int)FieldInstanceType.Option ? fDefinition.InitialValue : string.Empty)
            };

            return workItemFieldListDTO;
        }).ToArray();

        return newWorkItemListItemDTO;
    }

    private static WorkItemListItemDTO MapAtWorkItemReferenceDTO(AtworkItemReference workItemReference)
    {
        var newWorkItemListItemDTO = new WorkItemListItemDTO
        {
            WorkItemReferenceId = workItemReference.WorkItemReferenceId,
            WorkItemId = workItemReference.WorkItem.WorkItemId,
            QueueId = workItemReference.QueueId,
            QueueName = workItemReference.Queue?.Queue,
            LockedBy = workItemReference.WorkItem.LockedBy,
            Description = workItemReference.WorkItem.WorkItemName,
            Created = workItemReference.WorkItem.Created,
            Creator = workItemReference.WorkItem.Creator,
            SentBy = workItemReference.LastAction,
            AssignedTo = workItemReference.AssignedTo ?? string.Empty,
            SignedBy = workItemReference.WorkItem.Atdocuments?.FirstOrDefault()?.SignedBy ?? string.Empty

        };
        if (workItemReference.WorkItem != null)
        {
            newWorkItemListItemDTO.FieldList = workItemReference.WorkItem.AtfieldInstanceNumbers
                .Where(fInstance => fInstance.Field != null && fInstance.Field.Display)
                .Select(fiNumber =>
                    new WorkItemFieldListDTO
                    {
                        FieldId = fiNumber.FieldId,
                        FieldInstanceId = fiNumber.FieldInstanceId,
                        FieldProcessId = fiNumber.Field.ProcessId,
                        DataType = fiNumber.Field.DataType,
                        FieldName = fiNumber.Field.FieldName,
                        FieldValue = fiNumber.FieldValue.Value.ToString("G29", CultureInfo.InvariantCulture)
                    })
                .Union(workItemReference.WorkItem.AtfieldInstanceStrings
                .Where(fInstance => fInstance.Field != null && fInstance.Field.Display)
                .Select(fiString =>
                    new WorkItemFieldListDTO
                    {
                        FieldId = fiString.FieldId,
                        FieldInstanceId = fiString.FieldInstanceId,
                        FieldProcessId = fiString.Field.ProcessId,
                        FieldValue = fiString.FieldValue,
                        DataType = fiString.Field.DataType,
                        FieldName = fiString.Field.FieldName
                    }))
                .Union(workItemReference.WorkItem.AtfieldInstanceDates
                .Where(fInstance => fInstance.Field != null && fInstance.Field.Display)
                .Select(fiString =>
                    new WorkItemFieldListDTO
                    {
                        FieldId = fiString.FieldId,
                        FieldInstanceId = fiString.FieldInstanceId,
                        FieldProcessId = fiString.Field.ProcessId,
                        FieldValue = fiString.FieldValue.Value.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture),
                        DataType = fiString.Field.DataType,
                        FieldName = fiString.Field.FieldName
                    })).ToArray();
        }

        return newWorkItemListItemDTO;
    }

    public async Task<Response<string>> DeleteWorkItemsAsync(IEnumerable<int> workItemIds, CancellationToken ct = default)
    {
        try
        {
            var deletedRowsFromATWorkitem = await workItemReferenceRepository.DeleteWorkItemsAsync(workItemIds, ct);
            var msg = $"Deleted {deletedRowsFromATWorkitem} ATWorkItem rows (and related data).";
            return new Response<string>(msg, true);
        }
        catch (Exception ex)
        {
            logger.Error(ex, "DeleteWorkItemsAsync failed for ids: {Ids}", string.Join(",", workItemIds));
            throw;
        }
    }
}