using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;

using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;

using Ablera.Serdica.Microservice.Consumer.Attributes;
using Ablera.Serdica.Microservice.Consumer.Contracts.Asynchronous;
using Ablera.Serdica.DBModels.Serdica;
using Ablera.Serdica.Common.Tools.Exceptions;

using Ablera.Serdica.Authorization.Models;
using Ablera.Serdica.LocalCacheProvider.Contracts;
using Ablera.Serdica.Authority.Services;
using Ablera.Serdica.Authority.Models;
using Ablera.Serdica.Authentication.Constants;
using Ablera.Serdica.Extensions.RabbitMQ.Contracts;
using Polly;
using System.Configuration;

namespace Ablera.Serdica.NotificationService.Endpoints;

[Command("users_get_user_views", timeoutInSeconds: 5, methodName: "GET", allowedRoles: [SerdicaClaims.IsAuthenticated])]
public class UserViewsEndpoint(
    IEndpointRequestMessageProvider requestMessageProvider,
    SerdicaDbContext dbContext,
    RoutesTreeProvider routesProvider) 
        : IEndpointWithNoRequest<SerdicaRoute[]>
{
    public async Task<SerdicaRoute[]> 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 is not found!");

        var userRoles = await dbContext.UserAccounts
            .Where(x => x.UserAccountId == userAccount.UserAccountId)
            .SelectMany(x => x.UserRole1s)
            .Select(x => x.Id)
            .ToArrayAsync();
        if (!userRoles.Any())
        {
            throw new BaseResultException("account_has_no_roles".AsCode(), "Account has not roles set!");
        }

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

        return filteredRoutes;
    }
}
