using Ablera.Serdica.Microservice.Consumer.Attributes;
using Ablera.Serdica.Microservice.Consumer.Contracts.Asynchronous;
using Ablera.Serdica.Common.Tools.Exceptions;
using Ablera.Serdica.Authority.Services;
using System.Threading.Tasks;
using Ablera.Serdica.Authentication.Constants;
using Ablera.Serdica.DBModels.Serdica;
using System.Linq;
using Ablera.Serdica.Authority.Models;
using Ablera.Serdica.Extensions.RabbitMQ.Contracts;
using Ablera.Serdica.UserConfiguration.Models;
using System;
using Ablera.Serdica.Authority.Plugins.Base.Contracts;
using Ablera.Serdica.UserConfiguration.Contracts;

using static Ablera.Serdica.Authority.Constants.ConstantsClass;

namespace Ablera.Serdica.NotificationService.Endpoints;


public record UserConfigurationResponse
{ 
    public required UserConfigurationModel Configuration { get; init; }
    public required SerdicaRoute[] Routes { get; init; }
}

[Command("users_get_user_configuration", timeoutInSeconds: 10, methodName: "GET", allowedRoles: [SerdicaClaims.IsAuthenticated])]
public class UserConfigurationEndpoint(
    IEndpointRequestMessageProvider requestMessageProvider,
    SerdicaDbContext dbContext,
    RoutesTreeProvider routesProvider,
    IUserConfigurationRepository<UserConfigurationModel> repository)
        : IEndpointWithNoRequest<UserConfigurationResponse?>
{
    public async Task<UserConfigurationResponse?> ConsumeAsync()
    {
        var userAccount = dbContext.UserAccounts.Where(x => x.UserGuid == requestMessageProvider.RequestMessage.UserId)?.FirstOrDefault()
            ?? throw new BaseResultException("account_not_found".AsCode(), "Account associated with the session not found!");
        if (userAccount.LockAccount == YesKey)
        {
            throw new BaseResultException("account_locked".AsCode(), "Your account is locked. Please contact support.");
        }
        var userConfiguration = await repository.RetrieveAsync(userAccount.UserGuid);

        // Recursively filter the snapshot based on user roles and map to final DTO.
        var filteredRoutes = (routesProvider.Tree ?? [])
            .Select(route => route.FilterAndMapRoute(userConfiguration.Roles))
            .Where(r => r != null)
            .Cast<SerdicaRoute>()
            .ToList();

        return new UserConfigurationResponse
        {
            Configuration = userConfiguration,
            Routes = filteredRoutes?.ToArray() ?? []
        };
    }
}
