using Marco.Pms.Model.AppMenu;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using MongoDB.Bson;
using MongoDB.Driver;

namespace Marco.Pms.CacheHelper
{
    public class SidebarMenuHelper
    {
        private readonly IMongoCollection<MenuSection> _collection;
        private readonly ILogger<SidebarMenuHelper> _logger;

        public SidebarMenuHelper(IConfiguration configuration, ILogger<SidebarMenuHelper> logger)
        {
            _logger = logger;
            var connectionString = configuration["MongoDB:ModificationConnectionString"];
            var mongoUrl = new MongoUrl(connectionString);
            var client = new MongoClient(mongoUrl);
            var database = client.GetDatabase(mongoUrl.DatabaseName);
            _collection = database.GetCollection<MenuSection>("Menus");
        }

        public async Task<MenuSection?> CreateMenuSectionAsync(MenuSection section)
        {
            try
            {
                await _collection.InsertOneAsync(section);
                return section;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error occurred while adding MenuSection.");
                return null;
            }
        }

        public async Task<MenuSection?> UpdateMenuSectionAsync(Guid sectionId, MenuSection updatedSection)
        {
            try
            {
                var filter = Builders<MenuSection>.Filter.Eq(s => s.Id, sectionId);

                var update = Builders<MenuSection>.Update
                    .Set(s => s.Header, updatedSection.Header)
                    .Set(s => s.Title, updatedSection.Title)
                    .Set(s => s.Items, updatedSection.Items);

                var result = await _collection.UpdateOneAsync(filter, update);

                if (result.ModifiedCount > 0)
                {
                    return await _collection.Find(s => s.Id == sectionId).FirstOrDefaultAsync();
                }

                return null;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error updating MenuSection.");
                return null;
            }
        }

        public async Task<MenuSection?> AddMenuItemAsync(Guid sectionId, MenuItem newItem)
        {
            try
            {
                newItem.Id = Guid.NewGuid();

                var filter = Builders<MenuSection>.Filter.Eq(s => s.Id, sectionId);

                var update = Builders<MenuSection>.Update.Push(s => s.Items, newItem);

                var result = await _collection.UpdateOneAsync(filter, update);

                if (result.ModifiedCount > 0)
                {
                    return await _collection.Find(s => s.Id == sectionId).FirstOrDefaultAsync();
                }

                return null;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error adding menu item.");
                return null;
            }
        }

        public async Task<MenuItem?> UpdateMenuItemAsync(Guid sectionId, Guid itemId, MenuItem updatedItem)
        {
            try
            {
                var filter = Builders<MenuSection>.Filter.And(
                    Builders<MenuSection>.Filter.Eq(s => s.Id, sectionId),
                    Builders<MenuSection>.Filter.ElemMatch(s => s.Items, i => i.Id == itemId)
                );

                var update = Builders<MenuSection>.Update
                    .Set("Items.$.Text", updatedItem.Text)
                    .Set("Items.$.Icon", updatedItem.Icon)
                    .Set("Items.$.Available", updatedItem.Available)
                    .Set("Items.$.Link", updatedItem.Link)
                    .Set("Items.$.PermissionIds", updatedItem.PermissionIds);

                var result = await _collection.UpdateOneAsync(filter, update);

                if (result.ModifiedCount > 0)
                {
                    // Re-fetch section and return the updated item
                    var section = await _collection.Find(s => s.Id == sectionId).FirstOrDefaultAsync();
                    return section?.Items.FirstOrDefault(i => i.Id == itemId);
                }

                return null;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error updating MenuItem.");
                return null;
            }
        }

        public async Task<MenuSection?> AddSubMenuItemAsync(Guid sectionId, Guid itemId, SubMenuItem newSubItem)
        {
            try
            {
                newSubItem.Id = Guid.NewGuid();

                // Match the MenuSection and the specific MenuItem inside it
                var filter = Builders<MenuSection>.Filter.And(
                    Builders<MenuSection>.Filter.Eq(s => s.Id, sectionId),
                    Builders<MenuSection>.Filter.ElemMatch(s => s.Items, i => i.Id == itemId)
                );

                // Use positional operator `$` to target matched MenuItem and push into its Submenu
                var update = Builders<MenuSection>.Update.Push("Items.$.Submenu", newSubItem);

                var result = await _collection.UpdateOneAsync(filter, update);

                if (result.ModifiedCount > 0)
                {
                    return await _collection.Find(s => s.Id == sectionId).FirstOrDefaultAsync();
                }

                return null;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error adding submenu item.");
                return null;
            }
        }

        public async Task<SubMenuItem?> UpdateSubmenuItemAsync(Guid sectionId, Guid itemId, Guid subItemId, SubMenuItem updatedSub)
        {
            try
            {
                var filter = Builders<MenuSection>.Filter.Eq(s => s.Id, sectionId);

                var arrayFilters = new List<ArrayFilterDefinition>
                {
                    new BsonDocumentArrayFilterDefinition<BsonDocument>(
                        new BsonDocument("item._id", itemId.ToString())),
                    new BsonDocumentArrayFilterDefinition<BsonDocument>(
                        new BsonDocument("sub._id", subItemId.ToString()))
                };

                var update = Builders<MenuSection>.Update
                    .Set("Items.$[item].Submenu.$[sub].Text", updatedSub.Text)
                    .Set("Items.$[item].Submenu.$[sub].Available", updatedSub.Available)
                    .Set("Items.$[item].Submenu.$[sub].Link", updatedSub.Link)
                    .Set("Items.$[item].Submenu.$[sub].PermissionKeys", updatedSub.PermissionIds);

                var options = new UpdateOptions { ArrayFilters = arrayFilters };

                var result = await _collection.UpdateOneAsync(filter, update, options);

                if (result.ModifiedCount == 0)
                    return null;

                var updatedSection = await _collection.Find(x => x.Id == sectionId).FirstOrDefaultAsync();

                var subItem = updatedSection?.Items
                    .FirstOrDefault(i => i.Id == itemId)?
                    .Submenu
                    .FirstOrDefault(s => s.Id == subItemId);

                return subItem;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error updating SubMenuItem.");
                return null;
            }
        }



        public async Task<List<MenuSection>> GetAllMenuSectionsAsync(Guid tenantId)
        {
            var filter = Builders<MenuSection>.Filter.Eq(e => e.TenantId, tenantId);

            var result = await _collection
                .Find(filter)
                .ToListAsync();
            if (result.Any())
            {
                return result;
            }

            tenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26");
            filter = Builders<MenuSection>.Filter.Eq(e => e.TenantId, tenantId);

            result = await _collection
                .Find(filter)
                .ToListAsync();
            return result;
        }


    }
}
