using IWS5.Core.Enums;
using IWS5.Core.Models.Request;
using IWS5.DatabaseAccess.Interfaces;
using IWS5.DatabaseAccess.IwsDataContext;
using IWS5.DatabaseAccess.IwsDataModels;
using Microsoft.EntityFrameworkCore;
using Serilog;

namespace IWS5.DatabaseAccess.Repositories;

public class RightsRepository(GreenfieldPd2015Context context, ILogger logger) : IWSRepository<Atright>(context), IRightsRepository
{
    public async Task<List<Atright>> ListUserRelatedRights(string userName, ObjectType? objectType, ATRightAllowRight? allowRight = null, params Guid[] objectIds)
    {
        var query = context.Atusers.AsNoTracking()
            .Where(user => user.UserName == userName)
            .SelectMany(user => user.Parents)
            .SelectMany(parent => parent.Atrights);

        if (objectType != null)
        {
            query = query.Where(right => right.ObjectType == (int)objectType);
        }
        if (allowRight != null)
        {
            query = query.Where(right => right.AllowRights == (int)allowRight);
        }
        if (objectIds.Length > 0)
        {
            query = query.Where(right => objectIds.Contains(right.ObjectGuid));
        }

        var queryString = query.ToQueryString();
        logger.Information("Query: {QueryString}", queryString);

        var result = await query.ToListAsync();
        return result;
    }

    public async Task<List<Atright>> ListUserRelatedRights(string userName, ObjectType? objectType, params ATRightAllowRight[] allowRights)
    {
        var query = context.Atusers.AsNoTracking()
            .Where(user => user.UserName.ToLower() == userName.ToLower())
            .SelectMany(user => user.Parents)
            .SelectMany(parent => parent.Atrights);

        if (objectType != null)
        {
            query = query.Where(right => right.ObjectType == (int)objectType);
        }
        if (allowRights.Length > 0)
        {
            query = query.Where(right => allowRights.Contains((ATRightAllowRight)right.AllowRights));
        }
        var queryString = query.ToQueryString();
        logger.Information("Query: {QueryString}", queryString);

        var result = await query.ToListAsync();
        return result;
    }

    public async Task<List<Atright>> ListUserRelatedRights(string userName, ObjectType? objectType, ATRightAllowRight[] allowRights, Guid[] objectIds)
    {
        var query = context.Atusers.AsNoTracking()
            .Where(user => user.UserName.ToLower() == userName.ToLower())
            .SelectMany(user => user.Parents)
            .SelectMany(parent => parent.Atrights);

        if (objectType != null)
        {
            query = query.Where(right => right.ObjectType == (int)objectType);
        }
        if (allowRights.Length > 0)
        {
            query = query.Where(right => allowRights.Contains((ATRightAllowRight)right.AllowRights));
        }
        if (objectIds.Length > 0)
        {
            query = query.Where(right => objectIds.Contains(right.ObjectGuid));
        }
        
        var queryString = query.ToQueryString();
        logger.Information("Query: {QueryString}", queryString);

        var result = await query.ToListAsync();
        return result;
    }

    public async Task<int> UpdateRight(List<RightRequestItem> itemsToUpdate)
    {
        logger.Information("Updating rights for {Count} items", itemsToUpdate.Count);
        using (var transaction = context.Database.BeginTransaction())
        {
            try
            {
                foreach (var item in itemsToUpdate)
                {
                    logger.Information("Processing right for ObjectId: {ObjectId}, ObjectType: {ObjectType}, AllowRight: {AllowRight}, GroupId: {GroupId}",
                        item.ObjectId, item.ObjectType, item.AllowRight, item.GroupId);
                    var existingRight = context.Atrights
                        .FirstOrDefault(right => right.AllowRights == (int)item.AllowRight &&
                                                 right.ObjectGuid == item.ObjectId &&
                                                 right.ObjectType == (int)item.ObjectType &&
                                                 right.UserGuid == item.GroupId);

                    if (existingRight != null)
                    {
                        logger.Information("Existing right found for Object Type {Type} with id {ObjectId} with {right} right for group {group}, deleting it", 
                            item.ObjectType,item.ObjectId, item.AllowRight, item.GroupId);
                        context.Atrights.Remove(existingRight);
                    }
                    else
                    {
                        logger.Information("Inserting right for ObjectId: {ObjectId}, ObjectType: {ObjectType}, AllowRight: {AllowRight}, GroupId: {GroupId}",
                            item.ObjectId, item.ObjectType, item.AllowRight, item.GroupId);
                        context.Atrights.Add(new Atright
                        {
                            AllowRights = (int)item.AllowRight,
                            ObjectGuid = item.ObjectId,
                            ObjectType = (int)item.ObjectType,
                            UserGuid = item.GroupId
                        });
                    }
                }

                var count = context.SaveChanges();
                logger.Information("Successfully updated {Count} rights", count);
                await transaction.CommitAsync();
                return count;
            }
            catch (Exception ex)
            {
                await transaction.RollbackAsync();
                logger.Error(ex, "An error occurred while updating rights.");
                throw;
            }
        }
    }
}