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

namespace IWS5.DatabaseAccess.Repositories;

public class ProcessDocumentTemplateRightsRepository(GreenfieldPd2015Context context,
                                                     ILogger logger) : IWSRepository<AtprocessDocumentTemplateRight>(context), IProcessDocumentTemplateRightsRepository
{
    public async Task<int> UpdateLimitTemplate(List<UpdateProcessDefaultTemplateRequest> request)
    {
        logger.Information("Updating limit template for {Count} items", request.Count);
        using (var transaction = context.Database.BeginTransaction())
        {
            try
            {
                // Get ProcessId from the first request (assuming all have the same ProcessId)
                var processId = request[0].ProcessId;

                // 1) Find all existing templates for the process
                var existingTemplates = await context.AtprocessDocumentTemplateRights
                    .Where(template => template.ProcessObjectId == processId)
                    .ToListAsync();

                // Extract DocumentTemplateTypeIds from the request
                var requestTemplateTypeIds = request.Select(r => r.DocumentTemplateTypeId).ToHashSet();

                // 2) Find and delete records in DB not included in the request
                var templatesToDelete = existingTemplates
                    .Where(existing => !requestTemplateTypeIds.Contains(existing.DocumentTemplateObjectid))
                    .ToList();

                if (templatesToDelete.Any())
                {
                    //Delete all fields related to those templates
                    var docCabinetObjectIds = templatesToDelete
                        .Select(template => template.DocumentTemplateObjectid)
                        .ToList();

                    if (docCabinetObjectIds.Any())
                    {
                        // Fetch related CabinetIds for the templates
                        var docCabinetIds = await context.AtdocumentCabinets
                            .Where(template => docCabinetObjectIds.Contains(template.ObjectId))
                            .Select(cab => cab.CabinetId)
                            .ToListAsync();

                        if (docCabinetIds.Any())
                        {
                            // Fetch related Field ObjectIds for the cabinets
                            var fieldsObjectIds = await context.AtdocumentCabinetDefs
                                .Where(cab => docCabinetIds.Contains(cab.CabinetId))
                                .Select(cab => cab.ObjectId)
                                .ToListAsync();

                            if (fieldsObjectIds.Any())
                            {
                                // Directly delete related records from Atrights
                                var recordsDeletedCount = await context.Atrights
                                    .Where(field => fieldsObjectIds.Contains(field.ObjectGuid))
                                    .ExecuteDeleteAsync(); // Requires EF Core 7 or later

                                logger.Information("Deleted {Count} fields from the database for templates: {Templates}",
                                    recordsDeletedCount,
                                    string.Join(", ", docCabinetObjectIds));
                            }
                        }
                    }

                    context.AtprocessDocumentTemplateRights.RemoveRange(templatesToDelete);
                    logger.Information("Deleted {Count} templates from the database", templatesToDelete.Count);
                }

                // 3) Find and add records in the request not included in DB
                var existingTemplateTypeIds = existingTemplates
                    .Select(existing => existing.DocumentTemplateObjectid)
                    .ToHashSet();

                var templatesToAdd = request
                    .Where(req => !existingTemplateTypeIds.Contains(req.DocumentTemplateTypeId))
                    .Select(req => new AtprocessDocumentTemplateRight
                    {
                        ProcessObjectId = req.ProcessId,
                        DocumentTemplateObjectid = req.DocumentTemplateTypeId,
                        AllowRights = 10 // ATRightAllowRight = ProcessUseTemplate = 10
                    })
                    .ToList();

                if (templatesToAdd.Any())
                {
                    await context.AtprocessDocumentTemplateRights.AddRangeAsync(templatesToAdd);
                    logger.Information("Added {Count} new templates to the database", templatesToAdd.Count);
                }

                await context.SaveChangesAsync();
                await transaction.CommitAsync();

                logger.Information("Successfully updated limit template for process {ProcessId}", processId);

                return templatesToAdd.Count - templatesToDelete.Count;
            }
            catch (Exception ex)
            {
                await transaction.RollbackAsync();
                logger.Error(ex, "Error occurred while updating limit template");
                throw;
            }
        }
    }
}
