using IWS5.Core.DTO;
using IWS5.Core.Enums;
using IWS5.Core.Models;
using IWS5.Core.Models.Request;
using IWS5.Core.Services;
using IWS5.DatabaseAccess.Interfaces;
using Serilog;

namespace IWS5.Services;

public class ButtonService(IButtonRepository buttonRepository, 
    IEventDefinitionRepository eventDefinitionRepository, 
    IWorkItemReferenceRepository workItemReferenceRepository, 
    IQueueRepository queueRepository,
    ILogger logger)
    : IButtonService
{
    public async Task<CodeResponse<List<ButtonListItemDTO>>> ListButtons(ButtonRequest buttonRequest)
    {
        logger.Information("Starting ListButtons for User {UserName}", buttonRequest.UserName);

        var queue = await queueRepository.FindAsync(atQueue => atQueue.Id == buttonRequest.QueueId);
        if (queue == null)
        {
            logger.Error("No queue found matching the QueueId {QueueId}", buttonRequest.QueueId);
            return new CodeResponse<List<ButtonListItemDTO>>(ResponseCode.NotFound, $"No queue found matching the QueueId {buttonRequest.QueueId}");
        }

        var inboxEvent = await eventDefinitionRepository
            .FindAsync(atEvent => atEvent.EventId == queue.EventId 
                                  && (atEvent.EventTypeId == (int)ATEventType.User || atEvent.EventTypeId == (int)ATEventType.Queue),
                atEvent => atEvent.AtinboxEvents);
        if (inboxEvent == null)
        {
            logger.Information("No event found matching the EventId {EventId}", queue.EventId);
            return new CodeResponse<List<ButtonListItemDTO>>(ResponseCode.NotFound, $"No event found matching the EventId {queue.EventId}");
        }

        if (inboxEvent.EventTypeId == (int)ATEventType.Queue)
        {
            var allowedButtons = await buttonRepository.GetButtonsAndRights(buttonRequest);
            
            var allowedResponseBody = allowedButtons.Buttons
                .Select(button => new ButtonListItemDTO(
                    name: button.ButtonName,
                    value: button.ButtonValue,
                    allowedToClick: allowedButtons.Rights.Any(r =>
                        r.ObjectGuid == button.ObjectId && r.AllowRights == (int)ATRightAllowRight.ClickButton),
                    index: button.ButtonIndex))
                .ToList();
            
            return new CodeResponse<List<ButtonListItemDTO>>(ResponseCode.OK, null, allowedResponseBody);
        }
        
        var workItemReference = await workItemReferenceRepository
            .FindAsync(atWorkItemReference => atWorkItemReference.WorkItemReferenceId == buttonRequest.WorkItemReferenceId
            && !string.IsNullOrEmpty(atWorkItemReference.AssignedTo)
            && atWorkItemReference.AssignedTo.ToLower() == buttonRequest.UserName.ToLower());

        if (workItemReference == null)
        {
            logger.Information("No work item reference found for User {UserName} with WorkItemReferenceId {WorkItemReferenceId}",
                buttonRequest.UserName, buttonRequest.WorkItemReferenceId);
            return new CodeResponse<List<ButtonListItemDTO>>(ResponseCode.Unauthorized, $"User {buttonRequest.UserName} is not assigned to work item {buttonRequest.WorkItemReferenceId}");
        }
        
        var dbButtons = await buttonRepository.ListAsync(atButton => atButton.Queue.Id == buttonRequest.QueueId);
        var inboxButtons = dbButtons
            .Select(button => new ButtonListItemDTO(
                name: button.ButtonName,
                value: button.ButtonValue,
                allowedToClick: true,
                index: button.ButtonIndex))
            .ToList();
        
        
        return new CodeResponse<List<ButtonListItemDTO>>(ResponseCode.OK, null, inboxButtons);
    }
}