using AutoMapper;
using Marco.Pms.DataAccess.Data;
using Marco.Pms.Model.Dtos.Attendance;
using Marco.Pms.Model.Dtos.Employees;
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Entitlements;
using Marco.Pms.Model.Mapper;
using Marco.Pms.Model.Projects;
using Marco.Pms.Model.Utilities;
using Marco.Pms.Model.ViewModels.Activities;
using Marco.Pms.Model.ViewModels.Employee;
using Marco.Pms.Services.Helpers;
using Marco.Pms.Services.Hubs;
using Marco.Pms.Services.Service;
using Marco.Pms.Services.Service.ServiceInterfaces;
using MarcoBMS.Services.Helpers;
using MarcoBMS.Services.Service;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.CodeAnalysis;
using Microsoft.EntityFrameworkCore;
using System.Data;
using System.Net;

namespace MarcoBMS.Services.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    [Authorize]

    public class EmployeeController : ControllerBase
    {
        private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
        private readonly ApplicationDbContext _context;
        private readonly IServiceScopeFactory _serviceScopeFactory;
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly IEmailSender _emailSender;
        private readonly EmployeeHelper _employeeHelper;
        private readonly UserHelper _userHelper;
        private readonly GeneralHelper _generalHelper;
        private readonly IConfiguration _configuration;
        private readonly ILoggingService _logger;
        private readonly IHubContext<MarcoHub> _signalR;
        private readonly PermissionServices _permission;
        private readonly IMapper _mapper;
        private readonly IProjectServices _projectServices;
        private readonly Guid tenantId;
        private readonly Guid organizationId;


        public EmployeeController(IDbContextFactory<ApplicationDbContext> dbContextFactory,
            IServiceScopeFactory serviceScopeFactory,
            UserManager<ApplicationUser> userManager,
            IEmailSender emailSender,
            ApplicationDbContext context,
            EmployeeHelper employeeHelper,
            UserHelper userHelper,
            IConfiguration configuration,
            ILoggingService logger,
            IHubContext<MarcoHub> signalR,
            PermissionServices permission,
            IProjectServices projectServices,
            IMapper mapper,
            GeneralHelper generalHelper)
        {
            _dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory));
            _serviceScopeFactory = serviceScopeFactory;
            _context = context;
            _userManager = userManager;
            _emailSender = emailSender;
            _employeeHelper = employeeHelper;
            _userHelper = userHelper;
            _generalHelper = generalHelper;
            _configuration = configuration;
            _logger = logger;
            _signalR = signalR;
            _permission = permission;
            _projectServices = projectServices;
            _mapper = mapper;
            tenantId = _userHelper.GetTenantId();
            organizationId = _userHelper.GetCurrentOrganizationId();
        }

        [HttpGet]
        [Route("roles/{employeeId?}")]
        public async Task<IActionResult> GetRoles(Guid employeeId)
        {
            if (!ModelState.IsValid)
            {
                var errors = ModelState.Values
                    .SelectMany(v => v.Errors)
                    .Select(e => e.ErrorMessage)
                    .ToList();
                return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
            }
            Guid tenantId = GetTenantId();

            var empRoles = await _context.EmployeeRoleMappings.Where(c => c.EmployeeId == employeeId).Include(c => c.Role).Include(c => c.Employee).ToListAsync();
            if (empRoles.Any())
            {
                List<EmployeeRolesVM> roles = new List<EmployeeRolesVM>();

                foreach (EmployeeRoleMapping mapping in empRoles)
                {
                    roles.Add(new EmployeeRolesVM()
                    {
                        Id = mapping.Id,
                        EmployeeId = mapping.EmployeeId,
                        Name = mapping.Role != null ? mapping.Role.Role : null,
                        Description = mapping.Role != null ? mapping.Role.Description : null,
                        IsEnabled = mapping.IsEnabled,
                        RoleId = mapping.RoleId,
                    });
                }
                return Ok(ApiResponse<object>.SuccessResponse(roles, "Success.", 200));
            }
            else
            {
                return BadRequest(ApiResponse<object>.ErrorResponse("This employee has no assigned permissions.", "This employee has no assigned permissions.", 400));
            }
        }

        [HttpGet("list/organizations/{projectId}")]
        public async Task<IActionResult> GetEmployeesByProjectAsync(Guid projectId, [FromQuery] string searchString, [FromQuery] Guid? organizationId)
        {
            try
            {
                // Get the currently logged-in employee information
                var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();

                var projectTask = Task.Run(async () =>
                {
                    await using var context = await _dbContextFactory.CreateDbContextAsync();
                    return await context.Projects.FirstOrDefaultAsync(p => p.Id == projectId && p.TenantId == tenantId);
                });

                var tenantTask = Task.Run(async () =>
                {
                    await using var context = await _dbContextFactory.CreateDbContextAsync();
                    return await context.Tenants.FirstOrDefaultAsync(t => t.Id == tenantId);
                });

                await Task.WhenAll(projectTask, tenantTask);

                var project = projectTask.Result;
                var tenant = tenantTask.Result;

                if (project == null || tenant == null)
                {
                    _logger.LogWarning("Project {ProjectId} not found in database for tenant {TenantId}", projectId, tenantId);
                    return NotFound(ApiResponse<object>.ErrorResponse("Project not found", "Project not found", 404));
                }
                // Check if the logged-in employee has permission for the requested project
                var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId);
                if (!hasProjectPermission)
                {
                    _logger.LogWarning("User {EmployeeId} attempts to get employees for project {ProjectId} without permission", loggedInEmployee.Id, projectId);
                    return StatusCode(403, ApiResponse<object>.ErrorResponse("Access denied", "User does not have access to view the employees for this project", 403));
                }

                var organizationQuery = _context.ProjectOrgMappings
                    .Include(po => po.ProjectService)
                    .Where(po => po.ProjectService != null && po.ProjectService.ProjectId == projectId);

                if (loggedInEmployee.OrganizationId != project.PMCId && loggedInEmployee.OrganizationId != project.PromoterId && loggedInEmployee.OrganizationId != tenant.OrganizationId)
                {
                    organizationQuery = organizationQuery.Where(po => po.ParentOrganizationId == loggedInEmployee.OrganizationId || po.OrganizationId == loggedInEmployee.OrganizationId);
                }

                var organizationIds = await organizationQuery.Select(po => po.OrganizationId).ToListAsync();

                if (loggedInEmployee.OrganizationId == project.PMCId || loggedInEmployee.OrganizationId == project.PromoterId || loggedInEmployee.OrganizationId == tenant.OrganizationId)
                {
                    organizationIds.Add(project.PMCId);
                    organizationIds.Add(project.PromoterId);
                    organizationIds.Add(tenant.OrganizationId);
                }

                // Fetch employees allocated to the project matching the search criteria
                var employeesQuery = _context.Employees
                    .AsNoTracking()  // Improves performance by disabling change tracking for read-only query
                    .Include(e => e.JobRole)
                    .Where(e => (e.FirstName + " " + e.LastName).Contains(searchString) && organizationIds.Contains(e.OrganizationId));

                if (organizationId.HasValue)
                {
                    employeesQuery = employeesQuery.Where(e => e.OrganizationId == organizationId);
                }

                var employees = await employeesQuery
                    .ToListAsync();

                var result = employees.Select(e => _mapper.Map<EmployeeVM>(e)).Distinct().ToList();
                _logger.LogInfo("Employees fetched for project {ProjectId} by user {EmployeeId}. Count: {Count}", projectId, loggedInEmployee.Id, employees.Count);

                // Return the employee list wrapped in a successful API response
                return Ok(ApiResponse<object>.SuccessResponse(result, "Employee list fetched successfully", 200));
            }
            catch (Exception ex)
            {
                // Log the exception and return a 500 status code with error message
                _logger.LogError(ex, "Error occurred while fetching employees for project {ProjectId}", projectId);
                return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal server error", "An unexpected error occurred", 500));
            }
        }

        [HttpGet("list/{projectId?}")]
        public async Task<IActionResult> GetEmployeesByProjectAsync(Guid? projectId, [FromQuery] bool showInactive = false)
        {
            // Step 1: Validate incoming request model state
            if (!ModelState.IsValid)
            {
                var errors = ModelState.Values
                    .SelectMany(v => v.Errors)
                    .Select(e => e.ErrorMessage)
                    .ToList();

                _logger.LogWarning("Invalid model state in GetEmployeesByProject. Errors: {@Errors}", errors);
                return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
            }

            List<EmployeeVM> result = new List<EmployeeVM>();
            try
            {
                // Dependency injection scope for services
                using var scope = _serviceScopeFactory.CreateScope();

                // Step 2: Get logged-in employee details
                var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
                _logger.LogInfo("GetEmployeesByProject called. EmployeeId: {EmployeeId}, ProjectId: {ProjectId}, showInactive: {ShowInactive}",
                    loggedInEmployee.Id, projectId ?? Guid.Empty, showInactive);

                // Step 3: Fetch permissions concurrently
                var viewAllTask = Task.Run(async () =>
                {
                    var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
                    return await _permission.HasPermission(PermissionsMaster.ViewAllEmployees, loggedInEmployee.Id);
                });
                var viewTeamTask = Task.Run(async () =>
                {
                    var _permission = scope.ServiceProvider.GetRequiredService<PermissionServices>();
                    return await _permission.HasPermission(PermissionsMaster.ViewTeamMembers, loggedInEmployee.Id);
                });

                await Task.WhenAll(viewAllTask, viewTeamTask);

                var hasViewAllEmployeesPermission = viewAllTask.Result;
                var hasViewTeamMembersPermission = viewTeamTask.Result;

                List<Employee> employees = new List<Employee>();

                // Step 4: Query based on permission
                if (hasViewAllEmployeesPermission && !projectId.HasValue)
                {
                    // OrganizationId needs to be retrieved from loggedInEmployee or context based on your app's structure
                    var employeeQuery = _context.Employees
                        .AsNoTracking() // Optimize EF query for read-only operation[web:1][web:13][web:18]
                        .Include(e => e.JobRole)
                        .Where(e => e.OrganizationId == organizationId);

                    employeeQuery = showInactive
                        ? employeeQuery.Where(e => !e.IsActive)
                        : employeeQuery.Where(e => e.IsActive);

                    employees = await employeeQuery.ToListAsync();
                    _logger.LogInfo("Employee list fetched with full access. Count: {Count}", employees.Count);
                }
                else if (hasViewTeamMembersPermission && !showInactive && !projectId.HasValue)
                {
                    // Only active team members with limited permission
                    var projectIds = await _projectServices.GetMyProjectIdsAsync(tenantId, loggedInEmployee);

                    employees = await _context.ProjectAllocations
                        .AsNoTracking()
                        .Include(pa => pa.Employee)
                            .ThenInclude(e => e!.JobRole)
                        .Where(pa =>
                            projectIds.Contains(pa.ProjectId)
                            && pa.IsActive
                            && pa.Employee != null
                            && pa.Employee.IsActive
                            && pa.TenantId == tenantId)
                        .Select(pa => pa.Employee!)
                        .Distinct()
                        .ToListAsync();

                    _logger.LogInfo("Employee list fetched with limited access (active only). Count: {Count}", employees.Count);
                }

                // If a specific projectId is provided, override employee fetching to ensure strict project context
                if (projectId.HasValue)
                {
                    employees = await _context.ProjectAllocations
                        .AsNoTracking()
                        .Include(pa => pa.Employee)
                            .ThenInclude(e => e!.JobRole)
                        .Where(pa =>
                            pa.ProjectId == projectId
                            && pa.IsActive
                            && pa.Employee != null
                            && pa.Employee.IsActive
                            && pa.TenantId == tenantId)
                        .Select(pa => pa.Employee!)
                        .Distinct()
                        .ToListAsync();

                    _logger.LogInfo("Employee list fetched for specific project. ProjectId: {ProjectId}. Count: {Count}",
                        projectId, employees.Count);
                }

                // Step 5: Map to view model
                result = employees.Select(e => _mapper.Map<EmployeeVM>(e)).Distinct().ToList();

                _logger.LogInfo("Employees successfully fetched. EmployeeId: {EmployeeId} for ProjectId: {ProjectId}. Final Count: {Count}",
                    loggedInEmployee.Id, projectId ?? Guid.Empty, result.Count);

                return Ok(ApiResponse<object>.SuccessResponse(result, "Filter applied.", 200));
            }
            catch (Exception ex)
            {
                // Step 6: Error logging and response[web:6]
                _logger.LogError(ex, "Exception occurred while getting the list of employees");
                return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal server error. Please try again later.", null, 500));
            }
        }

        [HttpGet("basic")]
        public async Task<IActionResult> GetEmployeesByProjectBasic(Guid? projectId, [FromQuery] string? searchString, [FromQuery] bool allEmployee)
        {
            var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
            var employeeQuery = _context.Employees.Where(e => e.IsActive);
            if (projectId != null && projectId != Guid.Empty)
            {
                var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId.Value);
                if (!hasProjectPermission)
                {
                    _logger.LogWarning("User {EmployeeId} attempts to get employee for project {ProjectId}, but not have access to the project", loggedInEmployee.Id, projectId);
                    return StatusCode(403, ApiResponse<object>.ErrorResponse("Access denied", "User do not have access to view the list for this project", 403));
                }
                var employeeIds = await _context.ProjectAllocations.Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.TenantId == tenantId).Select(p => p.EmployeeId).ToListAsync();
                employeeQuery = employeeQuery.Where(e => employeeIds.Contains(e.Id));
            }
            else
            {
                employeeQuery = employeeQuery.Where(e => e.OrganizationId == organizationId);
            }
            if (!string.IsNullOrWhiteSpace(searchString))
            {
                var searchStringLower = searchString.ToLower();
                employeeQuery = employeeQuery.Where(e => (e.FirstName + " " + e.LastName).ToLower().Contains(searchStringLower));
            }

            var query = employeeQuery.OrderBy(e => e.FirstName);

            if (!allEmployee)
            {
                query = (IOrderedQueryable<Employee>)query.Take(10);
            }

            var response = await query
                .Select(e => _mapper.Map<BasicEmployeeVM>(e))
                .ToListAsync();
            return Ok(ApiResponse<object>.SuccessResponse(response, $"{response.Count} records of employees fetched successfully", 200));
        }

        /// <summary>
        /// Retrieves a paginated list of employees assigned to a specified project (if provided),
        /// with optional search functionality. 
        /// Ensures that the logged-in user has necessary permissions before accessing project employees.
        /// </summary>
        /// <param name="projectId">Optional project identifier to filter employees by project.</param>
        /// <param name="searchString">Optional search string to filter employees by name.</param>
        /// <param name="pageNumber">Page number for pagination (default = 1).</param>
        /// <returns>Paginated list of employees in BasicEmployeeVM format wrapped in ApiResponse.</returns>

        [HttpGet("search")]
        public async Task<IActionResult> GetEmployeesByProjectBasic(Guid? projectId, [FromQuery] string? searchString,
            [FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 10)
        {
            // Log API entry with context
            _logger.LogInfo("Fetching employees. ProjectId: {ProjectId}, SearchString: {SearchString}, PageNumber: {PageNumber}",
                                    projectId ?? Guid.Empty, searchString ?? "", pageNumber);

            var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
            _logger.LogDebug("Logged-in EmployeeId: {EmployeeId}", loggedInEmployee.Id);

            // Initialize query scoped by tenant
            var employeeQuery = _context.Employees.Where(e => e.TenantId == tenantId);

            // Filter by project if projectId is supplied
            if (projectId.HasValue && projectId.Value != Guid.Empty)
            {
                _logger.LogDebug("Project filter applied. Checking permission for EmployeeId: {EmployeeId} on ProjectId: {ProjectId}",
                                 loggedInEmployee.Id, projectId);

                // Validate project access permission
                var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId.Value);
                if (!hasProjectPermission)
                {
                    _logger.LogWarning("Access denied. EmployeeId: {EmployeeId} does not have permission for ProjectId: {ProjectId}",
                                       loggedInEmployee.Id, projectId);

                    return StatusCode(403, ApiResponse<object>.ErrorResponse(
                        "Access denied",
                        "User does not have access to view employees for this project",
                        403));
                }

                // Employees allocated to the project
                var employeeIds = await _context.ProjectAllocations
                                                .Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.TenantId == tenantId)
                                                .Select(pa => pa.EmployeeId)
                                                .ToListAsync();

                _logger.LogDebug("Project employees retrieved. Total linked employees found: {Count}", employeeIds.Count);

                // Apply project allocation filter
                employeeQuery = employeeQuery.Where(e => employeeIds.Contains(e.Id));
            }

            // Apply search filter if provided
            if (!string.IsNullOrWhiteSpace(searchString))
            {
                var searchStringLower = searchString.ToLower();
                _logger.LogDebug("Search filter applied. Search term: {SearchTerm}", searchStringLower);

                employeeQuery = employeeQuery.Where(e =>
                    (e.FirstName + " " + e.LastName).ToLower().Contains(searchStringLower));
            }

            // Pagination and Projection (executed in DB)
            var employees = await employeeQuery
                .Skip((pageNumber - 1) * pageSize)
                .Take(pageSize)
                .Select(e => _mapper.Map<BasicEmployeeVM>(e))
                .ToListAsync();

            _logger.LogInfo("Employees fetched successfully. Records returned: {Count}", employees.Count);

            return Ok(ApiResponse<object>.SuccessResponse(
                employees,
                $"{employees.Count} employee records fetched successfully",
                200));
        }

        [HttpGet]
        [Route("profile/get/{employeeId}")]
        public async Task<IActionResult> GetEmployeeProfileById(Guid employeeId)
        {
            if (!ModelState.IsValid)
            {
                var errors = ModelState.Values
                    .SelectMany(v => v.Errors)
                    .Select(e => e.ErrorMessage)
                    .ToList();
                return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
            }

            Employee emp = await _employeeHelper.GetEmployeeByID(employeeId);
            EmployeeVM employeeVM = EmployeeMapper.ToEmployeeVMFromEmployee(emp);

            return Ok(ApiResponse<object>.SuccessResponse(employeeVM, "Employee Profile.", 200));
        }

        private Guid GetTenantId()
        {
            return _userHelper.GetTenantId();
        }

        [HttpPost("old/manage")]
        public async Task<IActionResult> CreateUser([FromBody] CreateUserDto model)
        {
            Guid tenantId = _userHelper.GetTenantId();
            var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
            Guid employeeId = Guid.Empty;
            if (model == null)
                return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", "Invaild Data", 400));

            if (model.FirstName == null && model.PhoneNumber == null)
                return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", "Invaild Data", 400));

            string responsemessage = "";

            if (model.Email != null)
            {
                // Check if user already exists by email
                IdentityUser? existingUser = await _userHelper.GetRegisteredUser(model.Email);
                var existingEmployee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == model.Id && e.IsActive == true);

                if (existingUser != null)
                {
                    /* Identity user Exists - Create/update employee Employee */

                    // Update Employee record
                    existingEmployee = await _context.Employees.FirstOrDefaultAsync(e => e.Email == model.Email && e.Id == model.Id && e.IsActive == true);
                    if (existingEmployee != null)
                    {
                        existingEmployee = GetUpdateEmployeeModel(model, existingEmployee, existingUser);

                        _context.Employees.Update(existingEmployee);
                        await _context.SaveChangesAsync();
                        employeeId = existingEmployee.Id;
                        responsemessage = "User updated successfully.";
                    }
                    else
                    {
                        // Create Employee record if missing
                        //Employee newEmployee = GetNewEmployeeModel(model, TenantId, existingUser.Id);
                        //_context.Employees.Add(newEmployee);
                        return Conflict(ApiResponse<object>.ErrorResponse("Email already exist", "Email already exist", 409));
                    }


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

                    };
                    var isSeatsAvaiable = await _generalHelper.CheckSeatsRemainingAsync(tenantId);
                    if (!isSeatsAvaiable)
                    {
                        _logger.LogWarning("Maximum number of users reached for Tenant {TenantId}", tenantId);
                        return BadRequest(ApiResponse<object>.ErrorResponse("Maximum number of users reached. Cannot add new user", "Maximum number of users reached. Cannot add new user", 400));
                    }
                    // 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));

                    if (existingEmployee == null)
                    {
                        Employee newEmployee = GetNewEmployeeModel(model, tenantId, user.Id);
                        _context.Employees.Add(newEmployee);

                        await _context.SaveChangesAsync();
                        employeeId = newEmployee.Id;

                        /* 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);
                        }

                    }
                    else
                    {
                        existingEmployee.Email = model.Email;
                        existingEmployee = GetUpdateEmployeeModel(model, existingEmployee, user);

                        _context.Employees.Update(existingEmployee);
                        await _context.SaveChangesAsync();

                        employeeId = existingEmployee.Id;

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

                    }


                    responsemessage = "User created successfully. Password reset link is sent to registered email";
                }
            }
            else
            {
                var existingEmployee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == model.Id && e.IsActive == true);
                if (existingEmployee != null)
                {
                    existingEmployee = GetUpdateEmployeeModel(model, existingEmployee);
                    _context.Employees.Update(existingEmployee);
                    responsemessage = "User updated successfully.";
                    employeeId = existingEmployee.Id;
                }
                else
                {
                    // Create Employee record if missing
                    Employee newEmployee = GetNewEmployeeModel(model, tenantId, string.Empty);
                    _context.Employees.Add(newEmployee);
                    employeeId = newEmployee.Id;
                }
                await _context.SaveChangesAsync();
                responsemessage = "User created successfully.";

            }
            var notification = new { LoggedInUserId = LoggedInEmployee.Id, Keyword = "Employee", EmployeeId = employeeId };

            await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
            return Ok(ApiResponse<object>.SuccessResponse("Success.", responsemessage, 200));
        }

        [HttpPost("manage")]
        public async Task<IActionResult> CreateEmployeeAsync([FromBody] CreateUserDto model)
        {
            // Correlation and context capture for logs
            var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();

            {
                if (model == null)
                {
                    _logger.LogWarning("Model is null in CreateEmployeeAsync");
                    return BadRequest(ApiResponse<object>.ErrorResponse("Invalid payload", "Request body is required", 400));
                }

                // Basic validation
                if (model.HasApplicationAccess && string.IsNullOrWhiteSpace(model.Email))
                {
                    _logger.LogWarning("Application access requested but email is missing");
                    return BadRequest(ApiResponse<object>.ErrorResponse("Invalid email", "Application users must have a valid email", 400));
                }

                await using var transaction = await _context.Database.BeginTransactionAsync();
                try
                {
                    // Load existing employee if updating, constrained by organization scope
                    Employee? existingEmployee = null;
                    if (model.Id.HasValue && model.Id.Value != Guid.Empty)
                    {
                        existingEmployee = await _context.Employees
                            .FirstOrDefaultAsync(e => e.Id == model.Id);
                        if (existingEmployee == null)
                        {
                            _logger.LogInfo("Employee not found for update. Id={EmployeeId}", model.Id);
                            return NotFound(ApiResponse<object>.ErrorResponse("Employee not found", "Employee not found in database", 404));
                        }
                    }

                    // Identity user creation path (only if needed)
                    ApplicationUser? identityUserToCreate = null;
                    ApplicationUser? createdIdentityUser = null;

                    if (model.HasApplicationAccess)
                    {
                        // Only attempt identity resolution/creation if email supplied and either:
                        // - Creating new employee, or
                        // - Updating but existing employee does not have ApplicationUserId
                        var needsIdentity = string.IsNullOrWhiteSpace(existingEmployee?.ApplicationUserId);
                        if (needsIdentity && !string.IsNullOrWhiteSpace(model.Email))
                        {
                            var existingUser = await _userManager.FindByEmailAsync(model.Email);
                            if (existingUser == null)
                            {
                                // Seat check only when provisioning a new identity user
                                var isSeatsAvailable = await _generalHelper.CheckSeatsRemainingAsync(tenantId);
                                if (!isSeatsAvailable)
                                {
                                    _logger.LogWarning("Maximum users reached for Tenant {TenantId}. Cannot create identity user for {Email}", tenantId, model.Email);
                                    return BadRequest(ApiResponse<object>.ErrorResponse(
                                        "Maximum number of users reached. Cannot add new user",
                                        "Maximum number of users reached. Cannot add new user", 400));
                                }

                                identityUserToCreate = new ApplicationUser
                                {
                                    UserName = model.Email,
                                    Email = model.Email,
                                    EmailConfirmed = true
                                };
                            }
                            else
                            {
                                // If identity exists, re-use it; do not re-create
                                createdIdentityUser = existingUser;
                            }
                        }
                    }

                    // For create path: enforce uniqueness of employee email if applicable to business rules
                    // Consider adding a unique filtered index: (OrganizationId, Email) WHERE Email IS NOT NULL
                    if (!model.Id.HasValue || model.Id == Guid.Empty)
                    {
                        if (!string.IsNullOrWhiteSpace(model.Email))
                        {
                            var emailExists = await _context.Employees
                                .AnyAsync(e => e.Email == model.Email);
                            if (emailExists)
                            {
                                _logger.LogInfo("Employee email already exists. Email={Email}", model.Email);
                                return StatusCode(403, ApiResponse<object>.ErrorResponse(
                                    "Employee with email already exists",
                                    "Employee with this email already exists", 403));
                            }
                        }
                    }

                    // Create identity user if needed
                    if (identityUserToCreate != null && !string.IsNullOrWhiteSpace(identityUserToCreate.Email))
                    {
                        var createResult = await _userManager.CreateAsync(identityUserToCreate, "User@123");
                        if (!createResult.Succeeded)
                        {
                            _logger.LogWarning("Failed to create identity user for {Email}. Errors={Errors}",
                                identityUserToCreate.Email,
                                string.Join(", ", createResult.Errors.Select(e => $"{e.Code}:{e.Description}")));
                            return BadRequest(ApiResponse<object>.ErrorResponse("Failed to create user", createResult.Errors, 400));
                        }

                        createdIdentityUser = identityUserToCreate;
                        _logger.LogInfo("Identity user created. IdentityUserId={UserId}, Email={Email}",
                            createdIdentityUser.Id, createdIdentityUser.Email);
                    }


                    Guid employeeId;
                    EmployeeVM employeeVM;
                    string responseMessage;

                    if (existingEmployee != null)
                    {
                        // Update flow
                        _mapper.Map(model, existingEmployee);

                        if (createdIdentityUser != null && !string.IsNullOrWhiteSpace(createdIdentityUser.Email))
                        {
                            existingEmployee.ApplicationUserId = createdIdentityUser.Id;
                            await SendResetIfApplicableAsync(createdIdentityUser, existingEmployee.FirstName ?? "User");
                        }

                        await _context.SaveChangesAsync();

                        employeeId = existingEmployee.Id;
                        employeeVM = _mapper.Map<EmployeeVM>(existingEmployee);
                        responseMessage = "Employee Updated Successfully";

                        _logger.LogInfo("Employee updated. EmployeeId={EmployeeId}, Org={OrgId}", employeeId, existingEmployee.OrganizationId);
                    }
                    else
                    {
                        // Create flow
                        var newEmployee = _mapper.Map<Employee>(model);
                        newEmployee.IsSystem = false;
                        newEmployee.IsActive = true;
                        newEmployee.IsPrimary = false;

                        if (createdIdentityUser != null && !string.IsNullOrWhiteSpace(createdIdentityUser.Email))
                        {
                            newEmployee.ApplicationUserId = createdIdentityUser.Id;
                            await SendResetIfApplicableAsync(createdIdentityUser, newEmployee.FirstName ?? "User");
                        }

                        await _context.Employees.AddAsync(newEmployee);
                        await _context.SaveChangesAsync();

                        employeeId = newEmployee.Id;
                        employeeVM = _mapper.Map<EmployeeVM>(newEmployee);
                        responseMessage = "Employee Created Successfully";

                        _logger.LogInfo("Employee created. EmployeeId={EmployeeId}, Org={OrgId}", employeeId, newEmployee.OrganizationId);
                    }

                    await transaction.CommitAsync();

                    // SignalR notification
                    var notification = new
                    {
                        LoggedInUserId = loggedInEmployee.Id,
                        Keyword = "Employee",
                        EmployeeId = employeeId
                    };

                    // Consider broadcasting to tenant/organization group instead of Clients.All to avoid cross-tenant leaks:
                    // await _signalR.Clients.Group($"org:{model.OrganizationId}").SendAsync("NotificationEventHandler", notification);
                    await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);

                    _logger.LogInfo("Notification broadcasted for EmployeeId={EmployeeId}", employeeId);

                    return Ok(ApiResponse<object>.SuccessResponse(employeeVM, responseMessage, 200));
                }
                catch (DbUpdateException dbEx)
                {
                    await transaction.RollbackAsync();
                    _logger.LogError(dbEx, "Database exception occurred while managing employee");
                    return StatusCode(500, ApiResponse<object>.ErrorResponse(
                        "Internal exception occurred",
                        "Internal database exception has occurred", 500));
                }
                catch (Exception ex)
                {
                    await transaction.RollbackAsync();
                    _logger.LogError(ex, "Unhandled exception occurred while managing employee");
                    return StatusCode(500, ApiResponse<object>.ErrorResponse(
                        "Internal exception occurred",
                        "Internal exception has occurred", 500));
                }
            }
        }

        [HttpPost("manage-mobile")]
        public async Task<IActionResult> CreateUserMoblie([FromBody] MobileUserManageDto model)
        {
            Guid tenantId = _userHelper.GetTenantId();
            if (model == null)
            {
                _logger.LogWarning("User submitted empty or null employee information during employee creation or update in tenant {TenantId}", tenantId);
                return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", "Invaild Data", 400));
            }

            if (string.IsNullOrWhiteSpace(model.FirstName) || string.IsNullOrWhiteSpace(model.PhoneNumber))
            {
                _logger.LogWarning("User submitted empty or null first name or phone number during employee creation or update in tenant {TenantId}", tenantId);
                return BadRequest(ApiResponse<object>.ErrorResponse("First name and phone number are required fields.", "First name and phone number are required fields.", 400));
            }

            if (model.Id == null)
            {
                byte[]? imageBytes = null;
                if (!string.IsNullOrWhiteSpace(model.ProfileImage))
                {
                    try
                    {
                        imageBytes = Convert.FromBase64String(model.ProfileImage);
                    }
                    catch (FormatException)
                    {
                        return BadRequest(ApiResponse<object>.ErrorResponse("Invalid image format.", "Invalid image format", 400));
                    }
                }
                Employee employee = model.ToEmployeeFromMobileUserManageDto(tenantId, imageBytes);
                _context.Employees.Add(employee);
                await _context.SaveChangesAsync();

                EmployeeVM employeeVM = employee.ToEmployeeVMFromEmployee();

                _logger.LogInfo($"Employee {employee.FirstName} {employee.LastName} created in tenant {tenantId}");
                return Ok(ApiResponse<object>.SuccessResponse(employeeVM, "Employee created successfully", 200));
            }
            else
            {
                Employee? existingEmployee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == model.Id.Value);
                if (existingEmployee == null)
                {
                    _logger.LogWarning("User tries to update employee {EmployeeId} but not found in database", model.Id);
                    return NotFound(ApiResponse<object>.ErrorResponse("Employee not found", "Employee not found", 404));
                }
                byte[]? imageBytes = null;
                if (!string.IsNullOrWhiteSpace(model.ProfileImage))
                {
                    try
                    {
                        imageBytes = Convert.FromBase64String(model.ProfileImage);
                    }
                    catch (FormatException)
                    {
                        return BadRequest(ApiResponse<object>.ErrorResponse("Invalid image format.", "Invalid image format", 400));
                    }
                }

                imageBytes ??= existingEmployee.Photo;

                existingEmployee.FirstName = model.FirstName;
                existingEmployee.LastName = model.LastName;
                existingEmployee.Gender = model.Gender;
                existingEmployee.PhoneNumber = model.PhoneNumber;
                existingEmployee.JoiningDate = model.JoiningDate;
                existingEmployee.JobRoleId = model.JobRoleId;
                existingEmployee.Photo = imageBytes;

                await _context.SaveChangesAsync();

                EmployeeVM employeeVM = existingEmployee.ToEmployeeVMFromEmployee();

                _logger.LogInfo($"Employee {existingEmployee.FirstName} {existingEmployee.LastName} updated in tenant {tenantId}");
                return Ok(ApiResponse<object>.SuccessResponse(employeeVM, "Employee updated successfully", 200));
            }
        }

        [HttpPost("app/manage")]
        public async Task<IActionResult> CreateUserMobileAsync([FromBody] MobileUserManageDto model)
        {
            var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
            if (tenantId == Guid.Empty)
            {
                _logger.LogWarning("Tenant resolution failed in CreateUserMobile"); // structured warning
                return StatusCode(403, ApiResponse<object>.ErrorResponse("Unauthorized tenant context", "Unauthorized", 403));
            }

            if (model is null)
            {
                _logger.LogWarning("Null payload in CreateUserMobile for Tenant {TenantId}", tenantId); // validation log
                return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", "Invalid data", 400));
            }

            if (string.IsNullOrWhiteSpace(model.FirstName) || string.IsNullOrWhiteSpace(model.PhoneNumber))
            {
                _logger.LogWarning("Missing required fields FirstName/Phone for Tenant {TenantId}", tenantId); // validation log
                return BadRequest(ApiResponse<object>.ErrorResponse("First name and phone number are required.", "Required fields missing", 400));
            }

            // Strict Base64 parse
            byte[]? imageBytes = null;
            if (!string.IsNullOrWhiteSpace(model.ProfileImage))
            {
                try
                {
                    imageBytes = Convert.FromBase64String(model.ProfileImage);
                }
                catch (FormatException ex)
                {
                    _logger.LogError(ex, "Invalid base64 image in CreateUserMobile for Tenant {TenantId}", tenantId); // input issue
                    return BadRequest(ApiResponse<object>.ErrorResponse("Invalid image format.", "Invalid image", 400));
                }
            }
            if (model.Id == null || model.Id == Guid.Empty)
            {
                var emailExists = await _context.Employees
                .AnyAsync(e => e.Email == model.Email && e.OrganizationId == model.OrganizationId);

                if (emailExists && !string.IsNullOrWhiteSpace(model.Email))
                {
                    _logger.LogInfo("Employee email already exists in org. Email={Email}, Org={OrgId}", model.Email, model.OrganizationId);
                    return StatusCode(409, ApiResponse<object>.ErrorResponse("Employee with email already exists", "Employee with this email already exists", 409));
                }

                // Create path: map only allowed fields
                var employee = new Employee
                {
                    Id = Guid.NewGuid(),
                    TenantId = tenantId,
                    FirstName = model.FirstName.Trim(),
                    LastName = model.LastName?.Trim(),
                    Email = model.Email,
                    Gender = model.Gender,
                    PhoneNumber = model.PhoneNumber,
                    JoiningDate = model.JoiningDate,
                    JobRoleId = model.JobRoleId,
                    Photo = imageBytes,
                    OrganizationId = model.OrganizationId,
                    HasApplicationAccess = model.HasApplicationAccess,
                };

                if (!string.IsNullOrWhiteSpace(model.Email) && model.HasApplicationAccess)
                {
                    var existingUser = await _userManager.FindByEmailAsync(model.Email);
                    if (existingUser == null)
                    {
                        existingUser = new ApplicationUser
                        {
                            UserName = model.Email,
                            Email = model.Email,
                            EmailConfirmed = true
                        };
                        var createResult = await _userManager.CreateAsync(existingUser, "User@123");
                        if (!createResult.Succeeded)
                        {
                            _logger.LogWarning("Failed to create identity user for {Email}. Errors={Errors}",
                                existingUser.Email,
                                string.Join(", ", createResult.Errors.Select(e => $"{e.Code}:{e.Description}")));
                            return BadRequest(ApiResponse<object>.ErrorResponse("Failed to create user", createResult.Errors, 400));
                        }

                        await SendResetIfApplicableAsync(existingUser, employee.FirstName ?? "User");
                        employee.ApplicationUserId = existingUser.Id;
                    }
                }

                _context.Employees.Add(employee);
                await _context.SaveChangesAsync();

                var employeeVM = _mapper.Map<EmployeeVM>(employee);

                var notification = new
                {
                    LoggedInUserId = loggedInEmployee?.Id,
                    Keyword = "Employee",
                    EmployeeId = employee.Id
                };

                // Consider broadcasting to tenant/organization group instead of Clients.All to avoid cross-tenant leaks:
                // await _signalR.Clients.Group($"org:{model.OrganizationId}").SendAsync("NotificationEventHandler", notification);
                await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);

                _logger.LogInfo("Employee {EmployeeId} created in Tenant {TenantId}", employee.Id, tenantId); // success
                return Ok(ApiResponse<object>.SuccessResponse(employeeVM, "Employee created successfully", 200));
            }
            else
            {
                // Update path: fetch scoped to tenant
                var employeeId = model.Id.Value;
                var existingEmployee = await _context.Employees
                    .FirstOrDefaultAsync(e => e.Id == employeeId); // tenant-safe lookup

                if (existingEmployee is null)
                {
                    _logger.LogWarning("Update attempted for missing Employee {EmployeeId} in Tenant {TenantId}", employeeId, tenantId); // not found
                    return NotFound(ApiResponse<object>.ErrorResponse("Employee not found", "Not found", 404));
                }

                // Update allowed fields only
                existingEmployee.FirstName = model.FirstName.Trim();
                existingEmployee.LastName = model.LastName?.Trim();
                existingEmployee.Gender = model.Gender;
                existingEmployee.PhoneNumber = model.PhoneNumber;
                existingEmployee.JoiningDate = model.JoiningDate;
                existingEmployee.JobRoleId = model.JobRoleId;
                existingEmployee.OrganizationId = model.OrganizationId;
                existingEmployee.HasApplicationAccess = model.HasApplicationAccess;

                if (string.IsNullOrWhiteSpace(existingEmployee.Email) && !string.IsNullOrWhiteSpace(model.Email))
                {
                    var emailExists = await _context.Employees
                        .AnyAsync(e => e.Email == model.Email);

                    if (emailExists)
                    {
                        _logger.LogInfo("Employee email already exists in org. Email={Email}, Org={OrgId}", model.Email, model.OrganizationId);
                        return StatusCode(409, ApiResponse<object>.ErrorResponse("Employee with email already exists", "Employee with this email already exists", 409));
                    }
                    existingEmployee.Email = model.Email;
                }

                if (model.HasApplicationAccess && !string.IsNullOrWhiteSpace(model.Email) && string.IsNullOrWhiteSpace(existingEmployee.ApplicationUserId))
                {
                    var existingUser = await _userManager.FindByEmailAsync(model.Email);
                    if (existingUser == null)
                    {
                        existingUser = new ApplicationUser
                        {
                            UserName = model.Email,
                            Email = model.Email,
                            EmailConfirmed = true
                        };
                        var createResult = await _userManager.CreateAsync(existingUser, "User@123");
                        if (!createResult.Succeeded)
                        {
                            _logger.LogWarning("Failed to create identity user for {Email}. Errors={Errors}",
                                existingUser.Email,
                                string.Join(", ", createResult.Errors.Select(e => $"{e.Code}:{e.Description}")));
                            return BadRequest(ApiResponse<object>.ErrorResponse("Failed to create user", createResult.Errors, 400));
                        }

                        await SendResetIfApplicableAsync(existingUser, existingEmployee.FirstName ?? "User");
                        existingEmployee.ApplicationUserId = existingUser.Id;
                    }
                }

                if (imageBytes != null)
                {
                    existingEmployee.Photo = imageBytes;
                }

                await _context.SaveChangesAsync();

                var employeeVM = _mapper.Map<EmployeeVM>(existingEmployee);

                var notification = new
                {
                    LoggedInUserId = loggedInEmployee?.Id,
                    Keyword = "Employee",
                    EmployeeId = employeeId
                };

                // Consider broadcasting to tenant/organization group instead of Clients.All to avoid cross-tenant leaks:
                // await _signalR.Clients.Group($"org:{model.OrganizationId}").SendAsync("NotificationEventHandler", notification);
                await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);

                _logger.LogInfo("Employee {EmployeeId} updated in Tenant {TenantId}", existingEmployee.Id, tenantId); // success
                return Ok(ApiResponse<object>.SuccessResponse(employeeVM, "Employee updated successfully", 200));
            }
        }

        [HttpDelete("{id}")]
        public async Task<IActionResult> SuspendEmployee(Guid id, [FromQuery] bool active = false)
        {
            using var scope = _serviceScopeFactory.CreateScope();

            Guid tenantId = _userHelper.GetTenantId();
            var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();

            Employee? employee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == id && e.OrganizationId == organizationId);
            if (employee == null)
            {
                _logger.LogWarning("Employee with ID {EmploueeId} not found in database", id);
                return NotFound(ApiResponse<object>.ErrorResponse("Employee Not found successfully", "Employee Not found successfully", 404));
            }
            if (employee.IsSystem)
            {
                _logger.LogWarning("Employee with ID {LoggedEmployeeId} tries to suspend system-defined employee with ID {EmployeeId}", loggedInEmployee.Id, employee.Id);
                return BadRequest(ApiResponse<object>.ErrorResponse("System-defined employees cannot be suspended.", "System-defined employees cannot be suspended.", 400));
            }
            var assignedToTasks = await _context.TaskMembers.Where(t => t.EmployeeId == employee.Id).ToListAsync();
            if (assignedToTasks.Count != 0)
            {
                List<Guid> taskIds = assignedToTasks.Select(t => t.TaskAllocationId).ToList();
                var tasks = await _context.TaskAllocations.Where(t => taskIds.Contains(t.Id)).ToListAsync();

                foreach (var assignedToTask in assignedToTasks)
                {
                    var task = tasks.Find(t => t.Id == assignedToTask.TaskAllocationId);
                    if (task != null && task.CompletedTask == 0)
                    {
                        _logger.LogWarning("Employee with ID {EmployeeId} is currently assigned to any incomplete task", employee.Id);
                        return BadRequest(ApiResponse<object>.ErrorResponse("Employee is currently assigned to any incomplete task", "Employee is currently assigned to any incomplete task", 400));
                    }
                }
            }
            var attendance = await _context.Attendes.Where(a => a.EmployeeId == employee.Id && (a.OutTime == null || a.Activity == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE)).ToListAsync();
            if (attendance.Count != 0 && !active)
            {
                _logger.LogWarning("Employee with ID {EmployeeId} have any pending check-out or regularization requests", employee.Id);
                return BadRequest(ApiResponse<object>.ErrorResponse("Employee have any pending check-out or regularization requests", "Employee have any pending check-out or regularization requests", 400));
            }
            EmployeeVM employeeVM = new EmployeeVM();
            if (active)
            {
                employee.IsActive = true;
                var user = await _context.ApplicationUsers.FirstOrDefaultAsync(u => u.Id == employee.ApplicationUserId);
                if (user != null)
                {
                    user.IsActive = true;
                    _logger.LogInfo("The application user associated with employee ID {EmployeeId} has been actived.", employee.Id);

                }
                _logger.LogInfo("Employee with ID {EmployeId} Actived successfully", employee.Id);
                employeeVM = _mapper.Map<EmployeeVM>(employee);
            }
            else
            {
                employee.IsActive = false;
                var projectAllocations = await _context.ProjectAllocations.Where(a => a.EmployeeId == employee.Id).ToListAsync();
                if (projectAllocations.Count != 0)
                {
                    List<ProjectAllocation> allocations = new List<ProjectAllocation>();
                    foreach (var projectAllocation in projectAllocations)
                    {
                        projectAllocation.ReAllocationDate = DateTime.UtcNow;
                        projectAllocation.IsActive = false;
                        allocations.Add(projectAllocation);
                    }
                    _logger.LogInfo("Employee with ID {EmployeeId} has been removed from all assigned projects.", employee.Id);
                }
                var user = await _context.ApplicationUsers.FirstOrDefaultAsync(u => u.Id == employee.ApplicationUserId);
                if (user != null)
                {
                    user.IsActive = false;
                    _logger.LogInfo("The application user associated with employee ID {EmployeeId} has been suspended.", employee.Id);

                    var refreshTokens = await _context.RefreshTokens.AsNoTracking().Where(t => t.UserId == user.Id).ToListAsync();
                    if (refreshTokens.Count != 0)
                    {
                        _context.RefreshTokens.RemoveRange(refreshTokens);
                        _logger.LogInfo("Refresh tokens associated with employee ID {EmployeeId} has been removed.", employee.Id);
                    }

                }
                var roleMapping = await _context.EmployeeRoleMappings.AsNoTracking().Where(r => r.EmployeeId == employee.Id).ToListAsync();
                if (roleMapping.Count != 0)
                {
                    _context.EmployeeRoleMappings.RemoveRange(roleMapping);
                    _logger.LogInfo("Application role mapping associated with employee ID {EmployeeId} has been removed.", employee.Id);
                }
                _logger.LogInfo("Employee with ID {EmployeId} Deleted successfully", employee.Id);

            }
            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateException ex)
            {
                _logger.LogError(ex, "Exception Occured While activting/deactivting employee {EmployeeId}", employee.Id);
                return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal Error Occured", "Error occured while saving the entity", 500));
            }
            var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Employee", EmployeeId = employee.Id };

            await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);

            var _firebase = scope.ServiceProvider.GetRequiredService<IFirebaseService>();

            _ = Task.Run(async () =>
            {
                // --- Push Notification Section ---
                // This section attempts to send a test push notification to the user's device.
                // It's designed to fail gracefully and handle invalid Firebase Cloud Messaging (FCM) tokens.

                await _firebase.SendEmployeeSuspendMessageAsync(employee.Id, tenantId);

            });
            return Ok(ApiResponse<object>.SuccessResponse(employeeVM, "Employee Suspended successfully", 200));
        }
        private static Employee GetNewEmployeeModel(CreateUserDto model, Guid TenantId, string ApplicationUserId)
        {
            var newEmployee = new Employee
            {
                ApplicationUserId = String.IsNullOrEmpty(ApplicationUserId) ? null : ApplicationUserId,
                FirstName = model.FirstName,
                LastName = model.LastName,
                Email = model.Email,
                TenantId = TenantId,
                CurrentAddress = model.CurrentAddress,
                BirthDate = Convert.ToDateTime(model.BirthDate),
                EmergencyPhoneNumber = model.EmergencyPhoneNumber,
                EmergencyContactPerson = model.EmergencyContactPerson,
                Gender = model.Gender,
                MiddleName = model.MiddleName,
                PermanentAddress = model.PermanentAddress,
                PhoneNumber = model.PhoneNumber,
                Photo = null, // GetFileDetails(model.Photo).Result.FileData,
                JobRoleId = model.JobRoleId,
                JoiningDate = Convert.ToDateTime(model.JoiningDate),

            };
            return newEmployee;
        }
        private static Employee GetUpdateEmployeeModel(CreateUserDto model, Employee existingEmployee, IdentityUser? existingIdentityUser = null)
        {
            if (existingEmployee.ApplicationUserId == null && existingIdentityUser != null)
            {
                existingEmployee.ApplicationUserId = existingIdentityUser.Id;
            }
            existingEmployee.FirstName = model.FirstName;
            existingEmployee.LastName = model.LastName;
            existingEmployee.CurrentAddress = model.CurrentAddress;
            existingEmployee.BirthDate = Convert.ToDateTime(model.BirthDate);
            existingEmployee.JoiningDate = Convert.ToDateTime(model.JoiningDate);
            existingEmployee.EmergencyPhoneNumber = model.EmergencyPhoneNumber;
            existingEmployee.EmergencyContactPerson = model.EmergencyContactPerson;
            existingEmployee.Gender = model.Gender;
            existingEmployee.MiddleName = model.MiddleName;
            existingEmployee.PermanentAddress = model.PermanentAddress;
            existingEmployee.PhoneNumber = model.PhoneNumber;
            existingEmployee.Photo = existingEmployee.Photo; // GetFileDetails(model.Photo).Result.FileData,
            existingEmployee.JobRoleId = model.JobRoleId;

            return existingEmployee;
        }
        private static async Task<FileDetails> GetFileDetails(IFormFile file)
        {
            FileDetails info = new FileDetails();
            info.ContentType = file.ContentType;
            info.FileName = file.FileName;

            using (var memoryStream = new MemoryStream())
            {
                await file.CopyToAsync(memoryStream);
                info.FileData = memoryStream.ToArray();
            }
            return info;

        }

        // Prepare reset link sender helper
        private async Task SendResetIfApplicableAsync(ApplicationUser u, string firstName)
        {
            var token = await _userManager.GeneratePasswordResetTokenAsync(u);
            var resetLink = $"{_configuration["AppSettings:WebFrontendUrl"]}/reset-password?token={WebUtility.UrlEncode(token)}";
            await _emailSender.SendResetPasswordEmailOnRegister(u.Email ?? "", firstName, resetLink);
            _logger.LogInfo("Reset password email queued. Email={Email}", u.Email ?? "");
        }
    }
}
