using AutoMapper;
using Marco.Pms.DataAccess.Data;
using Marco.Pms.Model.Dtos.Organization;
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Entitlements;
using Marco.Pms.Model.OrganizationModel;
using Marco.Pms.Model.Utilities;
using Marco.Pms.Model.ViewModels.Activities;
using Marco.Pms.Model.ViewModels.Master;
using Marco.Pms.Model.ViewModels.Organization;
using Marco.Pms.Model.ViewModels.Projects;
using Marco.Pms.Services.Service;
using MarcoBMS.Services.Helpers;
using MarcoBMS.Services.Service;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Net;

namespace Marco.Pms.Services.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    [Authorize]
    public class OrganizationController : ControllerBase
    {
        private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
        private readonly IServiceScopeFactory _serviceScope;
        private readonly UserHelper _userHelper;
        private readonly Guid tenantId;
        private readonly IMapper _mapper;
        private readonly ILoggingService _logger;

        private static readonly Guid PMCProvider = Guid.Parse("b1877a3b-8832-47b1-bbe3-dc7e98672f49");
        private static readonly Guid ServiceProvider = Guid.Parse("5ee49bcd-b6d3-482f-9aaf-484afe04abec");
        private static readonly Guid SubContractorProvider = Guid.Parse("a283356a-9b02-4029-afb7-e65c703efdd4");
        private static readonly Guid superTenantId = Guid.Parse("b3466e83-7e11-464c-b93a-daf047838b26");
        public OrganizationController(IDbContextFactory<ApplicationDbContext> dbContextFactory,
            IServiceScopeFactory serviceScope,
            UserHelper userHelper,
            ILoggingService logger,
            IMapper mapper)
        {
            _dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory));
            _serviceScope = serviceScope ?? throw new ArgumentNullException(nameof(serviceScope));
            _userHelper = userHelper ?? throw new ArgumentNullException(nameof(userHelper));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
            _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
            tenantId = userHelper.GetTenantId();
        }
        #region =================================================================== Get Functions ===================================================================

        [HttpGet("list")]
        public async Task<IActionResult> GetOrganizarionListAsync([FromQuery] string? searchString, [FromQuery] double? sprid, [FromQuery] bool active = true,
            [FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 20)
        {
            await using var _context = await _dbContextFactory.CreateDbContextAsync();
            using var scope = _serviceScope.CreateScope();

            var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();

            var organizationQuery = _context.Organizations
                .Where(o => o.IsActive == active);

            if (sprid.HasValue)
            {
                organizationQuery = organizationQuery.Where(o => o.SPRID == sprid.Value);
            }
            else
            {
                var organizationIds = await _context.TenantOrgMappings.Where(to => to.TenantId == tenantId && to.IsActive).Select(to => to.OrganizationId).ToListAsync();
                organizationQuery = organizationQuery.Where(o => organizationIds.Contains(o.Id));

                if (!string.IsNullOrWhiteSpace(searchString))
                {
                    organizationQuery = organizationQuery.Where(sp =>
                        sp.Name.Contains(searchString)
                        //|| sp.ContactPerson.Contains(searchString)
                        //|| sp.Address.Contains(searchString)
                        //|| sp.Email.Contains(searchString)
                        //|| sp.ContactNumber.Contains(searchString)
                        );
                }
            }

            var totalCount = await organizationQuery.CountAsync();
            var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);

            var organizations = await organizationQuery
                .OrderBy(e => e.Name)
                .Skip((pageNumber - 1) * pageSize)
                .Take(pageSize)
                .ToListAsync();

            var createdByIds = organizations.Where(o => o.CreatedById != null).Select(o => o.CreatedById).ToList();
            var updatedByIds = organizations.Where(o => o.UpdatedById != null).Select(o => o.UpdatedById).ToList();

            var employees = await _context.Employees.Where(e => createdByIds.Contains(e.Id) || updatedByIds.Contains(e.Id)).ToListAsync();

            var vm = organizations.Select(o =>
            {
                var result = _mapper.Map<OrganizationVM>(o);
                result.CreatedBy = employees.Where(e => e.Id == o.CreatedById).Select(e => _mapper.Map<BasicEmployeeVM>(e)).FirstOrDefault();
                result.UpdatedBy = employees.Where(e => e.Id == o.UpdatedById).Select(e => _mapper.Map<BasicEmployeeVM>(e)).FirstOrDefault();
                return result;
            });

            var response = new
            {
                CurrentPage = pageNumber,
                TotalPages = totalPages,
                TotalEntites = totalCount,
                Data = vm,
            };

            return Ok(ApiResponse<object>.SuccessResponse(response, "Successfully fetched the Service Provider list", 200));
        }

        #endregion

        #region =================================================================== Post Functions ===================================================================

        [HttpPost("create")]
        public async Task<IActionResult> CreateOrganizationAsync([FromBody] CreateOrganizationDto model)
        {
            await using var _context = await _dbContextFactory.CreateDbContextAsync();
            using var scope = _serviceScope.CreateScope();
            await using var transaction = await _context.Database.BeginTransactionAsync();
            try
            {
                var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();

                var hasPermissionTask = Task.Run(async () =>
                {
                    var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
                    return await permissionService.HasPermission(PermissionsMaster.AddOrganization, loggedInEmployee.Id);
                });

                var IsPrimaryOrganizationTask = Task.Run(async () =>
                {
                    await using var context = await _dbContextFactory.CreateDbContextAsync();
                    return await context.Tenants.AnyAsync(t => t.OrganizationId == loggedInEmployee.OrganizationId);
                });

                await Task.WhenAll(hasPermissionTask, IsPrimaryOrganizationTask);

                var hasPermission = hasPermissionTask.Result;
                var IsPrimaryOrganization = IsPrimaryOrganizationTask.Result;

                if (!hasPermission && !IsPrimaryOrganization)
                {
                    return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "You do not have permission to create new service provider.", 403));
                }

                var lastOrganization = await _context.Organizations.OrderByDescending(sp => sp.SPRID).FirstOrDefaultAsync();

                var lastSPRID = lastOrganization != null ? lastOrganization.SPRID : 5400;

                Organization organization = _mapper.Map<Organization>(model);
                organization.SPRID = lastSPRID + 1;
                organization.CreatedAt = DateTime.UtcNow;
                organization.CreatedById = loggedInEmployee.Id;
                organization.IsActive = true;

                _context.Organizations.Add(organization);

                await _context.SaveChangesAsync();

                var user = new ApplicationUser
                {
                    UserName = model.Email,
                    Email = model.Email,
                    EmailConfirmed = true
                };

                var _configuration = scope.ServiceProvider.GetRequiredService<IConfiguration>();
                var _emailSender = scope.ServiceProvider.GetRequiredService<IEmailSender>();
                var _userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();

                // Create Identity User
                var result = await _userManager.CreateAsync(user, "User@123");
                if (!result.Succeeded)
                    return BadRequest(ApiResponse<object>.ErrorResponse("Failed to create user", result.Errors, 400));

                var jobRole = await _context.JobRoles.FirstOrDefaultAsync(jr => jr.Name == "Admin" && jr.TenantId == tenantId);
                if (jobRole == null)
                    jobRole = await _context.JobRoles.FirstOrDefaultAsync(jr => jr.TenantId == tenantId);

                var fullName = model.ContactPerson.Split(" ");

                Employee newEmployee = new Employee
                {
                    FirstName = fullName[0],
                    LastName = fullName[fullName.Length - 1],
                    Email = model.Email,
                    PermanentAddress = model.Address,
                    CurrentAddress = model.Address,
                    PhoneNumber = model.ContactNumber,
                    ApplicationUserId = user.Id,
                    JobRoleId = jobRole?.Id ?? Guid.Empty,
                    IsActive = true,
                    IsSystem = false,
                    IsPrimary = true,
                    OrganizationId = organization.Id
                };

                if (newEmployee.ApplicationUserId != null)
                {
                    newEmployee.HasApplicationAccess = true;
                }
                _context.Employees.Add(newEmployee);

                var serviceOrgMapping = model.ServiceIds.Select(s => new OrgServiceMapping
                {
                    ServiceId = s,
                    OrganizationId = organization.Id
                }).ToList();

                _context.OrgServiceMappings.AddRange(serviceOrgMapping);

                await _context.SaveChangesAsync();

                await transaction.CommitAsync();

                /* SEND USER REGISTRATION MAIL*/
                var token = await _userManager.GeneratePasswordResetTokenAsync(user);
                var resetLink = $"{_configuration["AppSettings:WebFrontendUrl"]}/reset-password?token={WebUtility.UrlEncode(token)}";
                if (newEmployee.FirstName != null)
                {
                    await _emailSender.SendResetPasswordEmailOnRegister(user.Email, newEmployee.FirstName, resetLink);
                }

                var response = _mapper.Map<OrganizationVM>(organization);
                response.CreatedBy = _mapper.Map<BasicEmployeeVM>(loggedInEmployee);

                return Ok(ApiResponse<object>.SuccessResponse(response, "Successfully created the service provider", 200));
            }
            catch (DbUpdateException dbEx)
            {
                await transaction.RollbackAsync();

                _logger.LogError(dbEx, "Database Exception has been occured");
                return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal error", "An database exception has been occured", 500));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception has been occured");
                return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal error", "An internal exception has been occured", 500));
            }
        }

        [HttpPost("assign/project")]
        public async Task<IActionResult> AssignOrganizationToProjectAsync([FromBody] AssignOrganizationDto model)
        {
            await using var _context = await _dbContextFactory.CreateDbContextAsync();
            using var scope = _serviceScope.CreateScope();
            await using var transaction = await _context.Database.BeginTransactionAsync();

            try
            {
                var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
                var todaysDate = DateTime.UtcNow.Date;

                var projectServicesTask = Task.Run(async () =>
                {
                    await using var context = await _dbContextFactory.CreateDbContextAsync();
                    return await context.ProjectServiceMappings
                    .Where(sp => model.ServiceIds.Contains(sp.ServiceId) && sp.ProjectId == model.ProjectId && sp.IsActive).ToListAsync();
                });

                var projectOrganizationsTask = Task.Run(async () =>
                {
                    await using var context = await _dbContextFactory.CreateDbContextAsync();
                    return await context.ProjectOrgMappings
                    .Include(po => po.ProjectService)
                    .Where(po => po.ProjectService != null && model.ServiceIds.Contains(po.ProjectService.ServiceId) && po.ProjectService.ProjectId == model.ProjectId).ToListAsync();
                });

                var serviceTask = Task.Run(async () =>
                {
                    await using var context = await _dbContextFactory.CreateDbContextAsync();
                    return await context.ServiceMasters.Where(s => model.ServiceIds.Contains(s.Id) && s.TenantId == tenantId).ToListAsync();
                });

                var organizationTypeTask = Task.Run(async () =>
                {
                    await using var context = await _dbContextFactory.CreateDbContextAsync();
                    return await context.OrgTypeMasters.FirstOrDefaultAsync(o => o.Id == model.OrganizationId);
                });

                var organizationTask = Task.Run(async () =>
                {
                    await using var context = await _dbContextFactory.CreateDbContextAsync();
                    return await context.Organizations.FirstOrDefaultAsync(o => o.Id == model.OrganizationId);
                });

                var parentorganizationTask = Task.Run(async () =>
                {
                    await using var context = await _dbContextFactory.CreateDbContextAsync();
                    return await context.Organizations.FirstOrDefaultAsync(o => o.Id == model.ParentOrganizationId);
                });

                var projectTask = Task.Run(async () =>
                {
                    await using var context = await _dbContextFactory.CreateDbContextAsync();
                    return await context.Projects.FirstOrDefaultAsync(p => p.Id == model.ProjectId);
                });

                var isPMCTask = Task.Run(async () =>
                {
                    await using var context = await _dbContextFactory.CreateDbContextAsync();
                    return await context.Projects.AnyAsync(p => p.Id == model.ProjectId && p.PMCId == loggedInEmployee.OrganizationId);
                });

                var isServiceProviderTask = Task.Run(async () =>
                {
                    await using var context = await _dbContextFactory.CreateDbContextAsync();
                    return await context.ProjectOrgMappings.AnyAsync(p => p.Id == model.ProjectId && p.OrganizationId == loggedInEmployee.OrganizationId
                    && p.OrganizationTypeId == ServiceProvider);
                });

                await Task.WhenAll(organizationTask, parentorganizationTask, projectTask, projectServicesTask, isPMCTask, isServiceProviderTask,
                    serviceTask, organizationTypeTask, projectOrganizationsTask);

                var services = serviceTask.Result;
                var organizationType = organizationTypeTask.Result;
                var organization = organizationTask.Result;
                var projectServices = projectServicesTask.Result;
                var parentorganization = parentorganizationTask.Result;
                var projectOrganizations = projectOrganizationsTask.Result;
                var project = projectTask.Result;
                var isPMC = isPMCTask.Result;
                var isServiceProvider = isServiceProviderTask.Result;

                if (organization == null)
                {
                    return NotFound(ApiResponse<object>.ErrorResponse("Organization not found", "Organization not found in database", 404));
                }
                if (project == null)
                {
                    return NotFound(ApiResponse<object>.ErrorResponse("Project not found", "Project not found in database", 404));
                }
                if (projectServices == null)
                {
                    return NotFound(ApiResponse<object>.ErrorResponse("Project Service not found", "Project Service not found in database", 404));
                }

                var serviceProviderTenantMapping = await _context.TenantOrgMappings
                    .FirstOrDefaultAsync(spt => spt.OrganizationId == model.OrganizationId && spt.TenantId == project.TenantId && spt.IsActive);

                if (serviceProviderTenantMapping == null)
                {
                    var newServiceProviderTenantMapping = new TenantOrgMapping
                    {
                        OrganizationId = organization.Id,
                        SPRID = organization.SPRID,
                        AssignedDate = DateTime.UtcNow,
                        IsActive = true,
                        AssignedById = loggedInEmployee.Id,
                        TenantId = project.TenantId
                    };
                    _context.TenantOrgMappings.Add(newServiceProviderTenantMapping);
                }

                List<ProjectOrgMapping> projectOrgMappings = new List<ProjectOrgMapping>();
                List<ProjectServiceMapping> projectServiceMappings = new List<ProjectServiceMapping>();

                if (isPMC && model.OrganizationTypeId != ServiceProvider && model.OrganizationTypeId != SubContractorProvider)
                {
                    return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "You don't have access to assign this type of organization", 403));
                }
                if (isServiceProvider && model.OrganizationTypeId == ServiceProvider)
                {
                    return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "You don't have access to assign this type of organization", 403));
                }

                foreach (var serviceId in model.ServiceIds)
                {
                    var service = await _context.ServiceMasters.FirstOrDefaultAsync(s => s.Id == serviceId);
                    if (service == null)
                    {
                        return NotFound(ApiResponse<object>.ErrorResponse("Service not found", "Service not found in database", 404));
                    }
                    var projectService = projectServices.FirstOrDefault(ps => ps.ServiceId == serviceId);
                    if (projectService == null)
                    {
                        projectService = new ProjectServiceMapping
                        {
                            Id = Guid.NewGuid(),
                            ProjectId = project.Id,
                            ServiceId = serviceId,
                            TenantId = project.TenantId,
                            PlannedStartDate = project.StartDate ?? DateTime.UtcNow,
                            PlannedEndDate = project.EndDate ?? DateTime.UtcNow,
                            ActualStartDate = DateTime.UtcNow,
                            IsActive = true
                        };
                        projectServiceMappings.Add(projectService);
                    }
                    var projectOrgMapping = new ProjectOrgMapping
                    {
                        ProjectServiceId = projectService.Id,
                        OrganizationId = model.OrganizationId,
                        OrganizationTypeId = model.OrganizationTypeId,
                        ParentOrganizationId = model.ParentOrganizationId ?? loggedInEmployee.OrganizationId,
                        AssignedDate = DateTime.UtcNow,
                        AssignedById = loggedInEmployee.Id,
                        TenantId = project.TenantId
                    };
                    var projectOrganization = projectOrganizations
                        .FirstOrDefault(po => po.ProjectService != null && po.ProjectService.ProjectId == project.Id && po.ProjectService.ServiceId == serviceId
                        && po.OrganizationId == model.OrganizationId);
                    if (projectOrganization != null)
                    {
                        return StatusCode(409, ApiResponse<object>.ErrorResponse("Organization is already assigned to this project", "Organization is already assigned to this project", 409));
                    }
                    projectOrgMappings.Add(projectOrgMapping);
                }

                if (projectServiceMappings.Any())
                {
                    _context.ProjectServiceMappings.AddRange(projectServiceMappings);
                    await _context.SaveChangesAsync();
                }

                _context.ProjectOrgMappings.AddRange(projectOrgMappings);

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

                var organizationVm = _mapper.Map<BasicOrganizationVm>(organization);
                var parentorganizationVm = _mapper.Map<BasicOrganizationVm>(parentorganization);
                var projectvm = _mapper.Map<BasicProjectVM>(project);

                var response = services.Select(s => new AssignOrganizationVm
                {
                    Project = projectvm,
                    OrganizationType = organizationType,
                    Organization = organizationVm,
                    ParentOrganization = parentorganizationVm,
                    Service = _mapper.Map<ServiceMasterVM>(s)
                }).ToList();

                return Ok(ApiResponse<object>.SuccessResponse(response, "Organization successfully assigned to the project", 200));
            }
            catch (DbUpdateException dbEx)
            {
                await transaction.RollbackAsync();

                _logger.LogError(dbEx, "Database Exception has been occured, While assigning the organization to project");
                return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal error", "An database exception has been occured", 500));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception has been occured, While assigned the organizatio to project");
                return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal error", "An internal exception has been occured", 500));
            }
        }

        [HttpPost("assign/tenant/{organizationId}")]
        public async Task<IActionResult> AssignOrganizationToTenantAsync(Guid organizationId)
        {
            await using var _context = await _dbContextFactory.CreateDbContextAsync();
            using var scope = _serviceScope.CreateScope();
            await using var transaction = await _context.Database.BeginTransactionAsync();
            try
            {
                var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();

                var serviceProviderTenantMappingTask = Task.Run(async () =>
                {
                    await using var context = await _dbContextFactory.CreateDbContextAsync();
                    return await context.TenantOrgMappings
                        .FirstOrDefaultAsync(spt => spt.OrganizationId == organizationId && spt.TenantId == tenantId && spt.IsActive);
                });

                var organizationTask = Task.Run(async () =>
                {
                    await using var context = await _dbContextFactory.CreateDbContextAsync();
                    return await context.Organizations
                        .FirstOrDefaultAsync(o => o.Id == organizationId);
                });

                await Task.WhenAll(serviceProviderTenantMappingTask, organizationTask);

                var serviceProviderTenantMapping = serviceProviderTenantMappingTask.Result;
                var organization = organizationTask.Result;

                if (organization == null)
                {
                    return NotFound(ApiResponse<object>.ErrorResponse("Organization not found", "Organization not found in database", 404));
                }

                if (serviceProviderTenantMapping == null)
                {
                    var newServiceProviderTenantMapping = new TenantOrgMapping
                    {
                        OrganizationId = organization.Id,
                        SPRID = organization.SPRID,
                        AssignedDate = DateTime.UtcNow,
                        IsActive = true,
                        AssignedById = loggedInEmployee.Id,
                        TenantId = tenantId
                    };
                    _context.TenantOrgMappings.Add(newServiceProviderTenantMapping);
                    await _context.SaveChangesAsync();
                    await transaction.CommitAsync();
                }
                var response = _mapper.Map<BasicOrganizationVm>(organization);
                return Ok(ApiResponse<object>.SuccessResponse(response, "Organization has been assigned to tenant", 200));
            }
            catch (DbUpdateException dbEx)
            {
                await transaction.RollbackAsync();

                _logger.LogError(dbEx, "Database Exception has been occured, While assigning the organization to project");
                return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal error", "An database exception has been occured", 500));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception has been occured, While assigned the organizatio to project");
                return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal error", "An internal exception has been occured", 500));
            }
        }
        #endregion

        #region =================================================================== Put Functions ===================================================================

        //[HttpPut("edit/{id}")]
        //public async Task<IActionResult> UpdateServiceProviderAsync(Guid id, [FromBody] UpdateOrganizationDto model)
        //{
        //    await using var _context = await _dbContextFactory.CreateDbContextAsync();
        //    using var scope = _serviceScope.CreateScope();

        //    var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();

        //    var clientTask = Task.Run(async () =>
        //    {
        //        await using var context = await _dbContextFactory.CreateDbContextAsync();
        //        return await context.Clients.FirstOrDefaultAsync(c => c.PrimaryEmployeeId == loggedInEmployee.Id && c.TenantId == tenantId);
        //    });
        //    var employeeTask = Task.Run(async () =>
        //    {
        //        await using var context = await _dbContextFactory.CreateDbContextAsync();
        //        return await context.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.OrganizationId == id && e.IsPrimary);
        //    });

        //    await Task.WhenAll(clientTask, employeeTask);

        //    var client = clientTask.Result;
        //    var employee = employeeTask.Result;

        //    if (employee == null)
        //    {
        //        return NotFound(ApiResponse<object>.ErrorResponse("Primary employee for service provider not found", "Primary employee for service provider not found in database", 400));
        //    }

        //    if (!(loggedInEmployee.ApplicationUser?.IsRootUser ?? false) && !loggedInEmployee.IsPrimary && client == null && employee.Id == loggedInEmployee.Id)
        //    {
        //        return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", "You do not have permission to create new service provider.", 403));
        //    }
        //    if (model.Id == id)
        //    {
        //        return BadRequest(ApiResponse<object>.ErrorResponse("Invalid Input", "Id from path parameters do not matches with id from model", 400));
        //    }
        //    var serviceProvider = await _context.ServiceProviders.FirstOrDefaultAsync(sp => sp.Id == model.Id);
        //    if (serviceProvider == null)
        //    {
        //        return NotFound(ApiResponse<object>.ErrorResponse("Service Provider not found", "Service Provider not found in database", 404));
        //    }
        //    _mapper.Map(model, serviceProvider);

        //    _context.ServiceProviders.Update(serviceProvider);

        //    var fullName = model.ContactPerson.Split(" ");

        //    employee.FirstName = fullName[0];
        //    employee.LastName = fullName[fullName.Length - 1];
        //    employee.CurrentAddress = model.Address;
        //    employee.PermanentAddress = model.Address;
        //    employee.PhoneNumber = model.PhoneNumber;

        //    _context.Employees.Update(employee);
        //    await _context.SaveChangesAsync();

        //    var response = _mapper.Map<OrganizationVM>(serviceProvider);
        //    return Ok(ApiResponse<object>.SuccessResponse(response, "Successfully updated the service provider", 200));
        //}

        #endregion

        #region =================================================================== Delete Functions ===================================================================

        //[HttpDelete("delete/{id}")]
        //public async Task<IActionResult> DeleteServiceProviderAsync(Guid id, [FromQuery] bool active)
        //{
        //    await using var _context = await _dbContextFactory.CreateDbContextAsync();
        //    using var scope = _serviceScope.CreateScope();

        //    var message = active ? "Restore" : "Delete";

        //    var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
        //    var client = await _context.Clients.FirstOrDefaultAsync(c => c.PrimaryEmployeeId == loggedInEmployee.Id && c.TenantId == tenantId);

        //    if (!(loggedInEmployee.ApplicationUser?.IsRootUser ?? false) && !loggedInEmployee.IsPrimary && client == null)
        //    {
        //        return StatusCode(403, ApiResponse<object>.ErrorResponse("Access Denied", $"You do not have permission to {message}d service provider.", 403));
        //    }

        //    var serviceProvider = await _context.ServiceProviders.FirstOrDefaultAsync(sp => sp.Id == id);
        //    if (serviceProvider == null)
        //    {
        //        return NotFound(ApiResponse<object>.ErrorResponse("Service Provider not Found", "Service Provider not Found in database", 404));
        //    }
        //    if (serviceProvider.IsActive == active)
        //    {
        //        return BadRequest(ApiResponse<object>.ErrorResponse($"Service Provider is already {message}d", $"Service Provider is already {message}d", 400));
        //    }

        //    var employeeIds = await _context.Employees.Where(e => e.ServiceProviderId == id).Select(e => e.Id).ToListAsync();

        //    var isPendingTask = await _context.TaskMembers.AnyAsync(tm => employeeIds.Contains(tm.EmployeeId));

        //    if (isPendingTask && !active)
        //    {
        //        return BadRequest(ApiResponse<object>.ErrorResponse("There is an unfinshed task, Service provider cannot be deleted", "There is an unfinshed task, Service provider cannot be deleted", 400));
        //    }

        //    serviceProvider.IsActive = active;

        //    if (!active)
        //    {
        //        var servicePeroviderTenant = await _context.ServiceProviderTenantMappings.AsNoTracking().Where(spt => spt.ServiceProviderId == id && spt.IsActive).ToListAsync();
        //        var newServiceProviderTenant = servicePeroviderTenant.Select(spt =>
        //        {
        //            spt.IsActive = false;
        //            return spt;

        //        }).ToList();
        //        _context.ServiceProviderTenantMappings.UpdateRange(newServiceProviderTenant);
        //    }

        //    await _context.SaveChangesAsync();
        //    return Ok(ApiResponse<object>.SuccessResponse(new { }, $"Service Provider is {message}d", 200));
        //}
        #endregion

        #region =================================================================== Helper Functions ===================================================================
        //private ServicesProviderFilter? TryDeserializeServicesProviderFilter(string? filter)
        //{
        //    if (string.IsNullOrWhiteSpace(filter))
        //    {
        //        return null;
        //    }

        //    var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
        //    ServicesProviderFilter? documentFilter = null;

        //    try
        //    {
        //        // First, try to deserialize directly. This is the expected case (e.g., from a web client).
        //        documentFilter = JsonSerializer.Deserialize<ServicesProviderFilter>(filter, options);
        //    }
        //    catch (JsonException ex)
        //    {
        //        _logger.LogError(ex, "[{MethodName}] Failed to directly deserialize filter. Attempting to unescape and re-parse. Filter: {Filter}", nameof(TryDeserializeServicesProviderFilter), filter);

        //        // If direct deserialization fails, it might be an escaped string (common with tools like Postman or some mobile clients).
        //        try
        //        {
        //            // Unescape the string first, then deserialize the result.
        //            string unescapedJsonString = JsonSerializer.Deserialize<string>(filter, options) ?? "";
        //            if (!string.IsNullOrWhiteSpace(unescapedJsonString))
        //            {
        //                documentFilter = JsonSerializer.Deserialize<ServicesProviderFilter>(unescapedJsonString, options);
        //            }
        //        }
        //        catch (JsonException ex1)
        //        {
        //            // If both attempts fail, log the final error and return null.
        //            _logger.LogError(ex1, "[{MethodName}] All attempts to deserialize the filter failed. Filter will be ignored. Filter: {Filter}", nameof(TryDeserializeServicesProviderFilter), filter);
        //            return null;
        //        }
        //    }
        //    return documentFilter;
        //}

        #endregion
    }
}
