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

namespace IWS5.Services;

public class ProcessService(
    IProcessRepository processRepository,
    IValidator<ListProcessAllowedTemplatesRequest> listProcessAllowedTemplatesRequestValidator,
    ILogger logger)
    : IProcessService
{
    private readonly TimeSpan _cacheExpiration = TimeSpan.FromHours(3);
    public async Task<Response<List<ProcessListItemDTO>>> ListProcesses(ListProcessRequest listProcessRequest)
    {
        logger.Information("Starting ListProcesses for User {UserName}", listProcessRequest.UserName);
        var allowedProcesses = await processRepository.GetAllowedProcesses(listProcessRequest.UserName);

        if (allowedProcesses.Count == 0)
        {
            logger.Error("No processes found for User {UserName}", listProcessRequest.UserName);
            return new Response<List<ProcessListItemDTO>>(null, false, $"No processes found for User {listProcessRequest.UserName}");
        }
        
        var result = allowedProcesses.Distinct()
            .Select(process => new ProcessListItemDTO
            {
                Id = process.ProcessId,
                Name = process.ProcessName,
                Version = $"v{process.ProcessVersion}",
            }).ToList();

        logger.Information("Successfully retrieved {ProcessCount} processes for User {UserName}", result.Count,
            listProcessRequest.UserName);
        return new Response<List<ProcessListItemDTO>>(result, true, null);
    }
    
    public async Task<Response<ATRightAllowRight[]>> ListProcessesPermissions(ListProcessAllowedRights listProcessAllowedTemplatesRequest)
    {
        var result = await processRepository.ListProcessesAllowedRights(listProcessAllowedTemplatesRequest);
        
        if (result.Length == 0)
        {
            logger.Error("No process permissions found for User {UserName}", listProcessAllowedTemplatesRequest.UserName);
            return new Response<ATRightAllowRight[]>([], false, null);
        }
        
        return new Response<ATRightAllowRight[]>(result, true, null);
    }
    
    public async Task<Response<ProcessAllowedTemplateListDTO>> ListProcessesAllowedTemplates(
        ListProcessAllowedTemplatesRequest listProcessAllowedTemplatesRequest)
    {
        logger.Information("Starting ListProcessesAllowedTemplates for ProcessId {ProcessId}", listProcessAllowedTemplatesRequest.ProcessId);

        await listProcessAllowedTemplatesRequestValidator.ValidateAndThrowAsync(listProcessAllowedTemplatesRequest);
        logger.Information("Validation successful for ProcessId {ProcessId}", listProcessAllowedTemplatesRequest.ProcessId);

        var result = await processRepository.ListProcessesAllowedTemplates(listProcessAllowedTemplatesRequest);
        logger.Information("Retrieved process details from repository for ProcessId {ProcessId}", listProcessAllowedTemplatesRequest.ProcessId);

        var dto = new ProcessAllowedTemplateListDTO(
            processId: result.ProcessId,
            templates: result.AtprocessDocumentTemplateRights
                .Select(right => new ProcessAllowedTemplateListItem(
                    templateId: right.DocumentTemplateObject.CabinetId,
                    templateName: right.DocumentTemplateObject.CabinetName,
                    isDefault: result.DefaultDocTemplate == right.DocumentTemplateObject.CabinetId)).ToArray());
        logger.Information("Mapped process details to DTO for ProcessId {ProcessId}", listProcessAllowedTemplatesRequest.ProcessId);

        return new Response<ProcessAllowedTemplateListDTO>(dto, true, null);
    }

    public async Task UpdateProcessDefaultTemplate(
        UpdateProcessDefaultTemplateRequest updateProcessDefaultTemplateRequest)
    {
        var result = await processRepository.UpdateProcessDefaultTemplate(updateProcessDefaultTemplateRequest);
        logger.Information("Successfully updated default template for process {ProcessId}",
            updateProcessDefaultTemplateRequest.ProcessId);
    }
}