using System.Text;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.EntityFrameworkCore;
using PowderCoating.Application.DTOs.Common;
using PowderCoating.Application.DTOs.User;
using PowderCoating.Application.Interfaces;
using PowderCoating.Core.Entities;
using PowderCoating.Core.Interfaces;
using PowderCoating.Shared.Constants;

namespace PowderCoating.Web.Controllers;

/// <summary>
/// Controller for managing users within a company (CompanyAdmin only)
/// </summary>
[Authorize(Policy = AppConstants.Policies.CompanyAdminOnly)]
public class CompanyUsersController : Controller
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly ITenantContext _tenantContext;
    private readonly ILogger<CompanyUsersController> _logger;
    private readonly IUnitOfWork _unitOfWork;
    private readonly ISubscriptionService _subscriptionService;
    private readonly IEmailService _emailService;

    public CompanyUsersController(
        UserManager<ApplicationUser> userManager,
        ITenantContext tenantContext,
        ILogger<CompanyUsersController> logger,
        IUnitOfWork unitOfWork,
        ISubscriptionService subscriptionService,
        IEmailService emailService)
    {
        _userManager = userManager;
        _tenantContext = tenantContext;
        _logger = logger;
        _unitOfWork = unitOfWork;
        _subscriptionService = subscriptionService;
        _emailService = emailService;
    }

    /// <summary>
    /// Lists users belonging to the current tenant company with search, sort, and pagination.
    /// The query filters by <c>CompanyId</c> and requires a non-null <c>CompanyRole</c> to
    /// exclude SuperAdmin platform users, who have <c>CompanyRole == null</c> and should never
    /// appear in a company's own user list. Non-SuperAdmin users without a valid CompanyId are
    /// rejected early with a redirect, preventing a data-access error from propagating to the view.
    /// </summary>
    // GET: CompanyUsers
    public async Task<IActionResult> Index(
        string? searchTerm,
        string? roleFilter,
        string? sortColumn,
        string sortDirection = "asc",
        int pageNumber = 1,
        int pageSize = 25)
    {
        try
        {
            var companyId = _tenantContext.GetCurrentCompanyId();
            var isSuperAdmin = _tenantContext.IsSuperAdmin();

            _logger.LogInformation("CompanyUsers.Index - User: {User}, CompanyId: {CompanyId}, IsSuperAdmin: {IsSuperAdmin}",
                User.Identity?.Name, companyId, isSuperAdmin);

            // SECURITY: Non-SuperAdmin users MUST have a valid CompanyId
            if (!companyId.HasValue && !isSuperAdmin)
            {
                _logger.LogWarning("Non-SuperAdmin user {User} attempted to access CompanyUsers without a valid CompanyId",
                    User.Identity?.Name);
                TempData["Error"] = "Unable to determine your company. Please contact support.";
                return RedirectToAction("Index", "Home");
            }

            // If SuperAdmin and no company selected, show all users or redirect to company selection
            if (isSuperAdmin && !companyId.HasValue)
            {
                TempData["Info"] = "As SuperAdmin, please select a company to manage its users, or use the Users admin page for platform-wide user management.";
                return RedirectToAction("Index", "Home");
            }

            // SECURITY: Ensure CompanyId has a value before querying
            if (!companyId.HasValue)
            {
                _logger.LogError("CompanyId is null after validation checks - this should never happen. User: {User}",
                    User.Identity?.Name);
                TempData["Error"] = "An error occurred determining your company access.";
                return RedirectToAction("Index", "Home");
            }

            // Create and validate grid request
            var gridRequest = new GridRequest
            {
                PageNumber = pageNumber,
                PageSize = pageSize,
                SortColumn = sortColumn ?? "Name",
                SortDirection = sortDirection,
                SearchTerm = searchTerm
            };
            gridRequest.Validate();

            // Build query for company users (excluding SuperAdmins)
            var query = _userManager.Users
                .Where(u => u.CompanyId == companyId.Value && u.CompanyRole != null);

            // Apply search filter
            if (!string.IsNullOrWhiteSpace(searchTerm))
            {
                var search = searchTerm.ToLower();
                query = query.Where(u =>
                    (u.FirstName != null && u.FirstName.ToLower().Contains(search)) ||
                    (u.LastName != null && u.LastName.ToLower().Contains(search)) ||
                    (u.Email != null && u.Email.ToLower().Contains(search)) ||
                    (u.Department != null && u.Department.ToLower().Contains(search)));
            }

            // Apply role filter
            if (!string.IsNullOrWhiteSpace(roleFilter))
            {
                query = query.Where(u => u.CompanyRole == roleFilter);
            }

            // Get total count before pagination
            var totalCount = await query.CountAsync();

            // Apply sorting
            query = gridRequest.SortColumn switch
            {
                "Name" => gridRequest.SortDirection == "asc"
                    ? query.OrderBy(u => u.LastName).ThenBy(u => u.FirstName)
                    : query.OrderByDescending(u => u.LastName).ThenByDescending(u => u.FirstName),
                "Email" => gridRequest.SortDirection == "asc"
                    ? query.OrderBy(u => u.Email)
                    : query.OrderByDescending(u => u.Email),
                "CompanyRole" => gridRequest.SortDirection == "asc"
                    ? query.OrderBy(u => u.CompanyRole)
                    : query.OrderByDescending(u => u.CompanyRole),
                "Department" => gridRequest.SortDirection == "asc"
                    ? query.OrderBy(u => u.Department)
                    : query.OrderByDescending(u => u.Department),
                "IsActive" => gridRequest.SortDirection == "asc"
                    ? query.OrderBy(u => u.IsActive)
                    : query.OrderByDescending(u => u.IsActive),
                "LastLoginDate" => gridRequest.SortDirection == "asc"
                    ? query.OrderBy(u => u.LastLoginDate)
                    : query.OrderByDescending(u => u.LastLoginDate),
                _ => query.OrderBy(u => u.LastName).ThenBy(u => u.FirstName)
            };

            // Apply pagination
            var users = await query
                .Skip((gridRequest.PageNumber - 1) * gridRequest.PageSize)
                .Take(gridRequest.PageSize)
                .ToListAsync();

            _logger.LogInformation("Retrieved {Count} company users (excluding platform users) for company {CompanyId}",
                users.Count, companyId.Value);

            // Map to DTOs
            var userDtos = users.Select(u => new CompanyUserListDto
            {
                Id = u.Id,
                Email = u.Email ?? "",
                FirstName = u.FirstName,
                LastName = u.LastName,
                CompanyRole = u.CompanyRole,
                Department = u.Department,
                IsActive = u.IsActive,
                IsBanned = u.IsBanned,
                HireDate = u.HireDate,
                LastLoginDate = u.LastLoginDate
            }).ToList();

            var pagedResult = PagedResult<CompanyUserListDto>.From(gridRequest, userDtos, totalCount);

            // Set ViewBag for sorting and filters
            ViewBag.SearchTerm = searchTerm;
            ViewBag.RoleFilter = roleFilter;
            ViewBag.SortColumn = gridRequest.SortColumn;
            ViewBag.SortDirection = gridRequest.SortDirection;

            return View(pagedResult);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error retrieving company users");
            TempData["Error"] = "An error occurred while loading users.";
            return View(new PagedResult<CompanyUserListDto>());
        }
    }

    /// <summary>
    /// Renders the new-user form after checking the subscription user-count limit. If the
    /// plan limit is already reached, the user is redirected to the index with an explanatory
    /// message rather than allowing the form to be submitted and fail later. SuperAdmins bypass
    /// the limit check so platform operators are never locked out.
    /// </summary>
    // GET: CompanyUsers/Create
    public async Task<IActionResult> Create()
    {
        var isSuperAdmin = _tenantContext.IsSuperAdmin();
        var companyId = _tenantContext.GetCurrentCompanyId();

        if (!isSuperAdmin && companyId.HasValue &&
            !await _subscriptionService.CanAddUserAsync(companyId.Value))
        {
            var (used, max) = await _subscriptionService.GetUserCountAsync(companyId.Value);
            TempData["Error"] = $"You have reached your plan limit of {max} users. " +
                "Please upgrade your plan to add more users.";
            return RedirectToAction(nameof(Index));
        }

        var model = new CreateCompanyUserDto
        {
            HireDate = DateTime.UtcNow,
            CompanyRole = AppConstants.CompanyRoles.Viewer
        };

        return View(model);
    }

    /// <summary>
    /// Creates a new company user, enforcing the subscription user-count limit and a whitelist
    /// of valid <c>CompanyRole</c> values (preventing callers from submitting a null role to
    /// create a SuperAdmin-equivalent account). CompanyAdmin users automatically receive all
    /// per-feature permissions unless a SuperAdmin is explicitly customising them. A legacy
    /// ASP.NET Identity role (Administrator / Manager / Employee / ReadOnly) is also assigned
    /// to satisfy policy checks that still reference the role system.
    /// </summary>
    // POST: CompanyUsers/Create
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(CreateCompanyUserDto model)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        try
        {
            var companyId = _tenantContext.GetCurrentCompanyId();
            var isSuperAdmin = _tenantContext.IsSuperAdmin();

            if (!companyId.HasValue && !isSuperAdmin)
            {
                TempData["Error"] = "Unable to determine your company.";
                return RedirectToAction(nameof(Index));
            }

            if (isSuperAdmin && !companyId.HasValue)
            {
                TempData["Error"] = "Please select a company context to create users.";
                return RedirectToAction(nameof(Index));
            }

            // Subscription limit check (skip for SuperAdmin)
            if (!isSuperAdmin && companyId.HasValue)
            {
                if (!await _subscriptionService.CanAddUserAsync(companyId.Value))
                {
                    var (used, max) = await _subscriptionService.GetUserCountAsync(companyId.Value);
                    ModelState.AddModelError(string.Empty,
                        $"You have reached your plan limit of {max} users. " +
                        "Please upgrade your plan to add more users.");
                    return View(model);
                }
            }

            // SECURITY: Ensure CompanyRole is a valid company role (not null/empty, which would create a platform user)
            var validCompanyRoles = new[]
            {
                AppConstants.CompanyRoles.CompanyAdmin,
                AppConstants.CompanyRoles.Manager,
                AppConstants.CompanyRoles.Accountant,
                AppConstants.CompanyRoles.Worker,
                AppConstants.CompanyRoles.Viewer
            };

            if (string.IsNullOrWhiteSpace(model.CompanyRole) || !validCompanyRoles.Contains(model.CompanyRole))
            {
                ModelState.AddModelError("CompanyRole", "Invalid company role selected.");
                return View(model);
            }

            // Check if user already exists
            var existingUser = await _userManager.FindByEmailAsync(model.Email);
            if (existingUser != null)
            {
                ModelState.AddModelError("Email", "A user with this email already exists.");
                return View(model);
            }

            // Company Admins always get all permissions (unless a SuperAdmin is explicitly customizing them)
            var isCompanyAdmin = model.CompanyRole == AppConstants.CompanyRoles.CompanyAdmin;
            var forceAllPermissions = isCompanyAdmin && !isSuperAdmin;

            // Create user
            var user = new ApplicationUser
            {
                UserName = model.Email,
                Email = model.Email,
                EmailConfirmed = true,
                FirstName = model.FirstName,
                LastName = model.LastName,
                EmployeeNumber = model.EmployeeNumber,
                CompanyId = companyId!.Value,
                CompanyRole = model.CompanyRole,
                Department = model.Department,
                Position = model.Position,
                PhoneNumber = model.Phone,
                HireDate = model.HireDate,
                IsActive = true,
                // SuperAdmins can set individual permissions even for CompanyAdmin users
                CanManageJobs = forceAllPermissions || model.CanManageJobs,
                CanManageInventory = forceAllPermissions || model.CanManageInventory,
                CanManageCustomers = forceAllPermissions || model.CanManageCustomers,
                CanCreateQuotes = forceAllPermissions || model.CanCreateQuotes,
                CanApproveQuotes = forceAllPermissions || model.CanApproveQuotes,
                CanManageCalendar = forceAllPermissions || model.CanManageCalendar,
                CanViewCalendar = forceAllPermissions || model.CanViewCalendar,
                CanManageProducts = forceAllPermissions || model.CanManageProducts,
                CanViewProducts = forceAllPermissions || model.CanViewProducts,
                CanManageEquipment = forceAllPermissions || model.CanManageEquipment,
                CanManageVendors = forceAllPermissions || model.CanManageVendors,
                CanManageMaintenance = forceAllPermissions || model.CanManageMaintenance,
                CanManageInvoices = forceAllPermissions || model.CanManageInvoices,
                CanViewReports = forceAllPermissions || model.CanViewReports,
                CanManageBills = forceAllPermissions || model.CanManageBills,
                CanManageAccounting = forceAllPermissions || model.CanManageAccounting
            };

            var result = await _userManager.CreateAsync(user, model.Password);

            if (result.Succeeded)
            {
                // Assign legacy role based on company role
                var legacyRole = model.CompanyRole switch
                {
                    AppConstants.CompanyRoles.CompanyAdmin => AppConstants.Roles.Administrator,
                    AppConstants.CompanyRoles.Manager => AppConstants.Roles.Manager,
                    AppConstants.CompanyRoles.Accountant => AppConstants.Roles.Employee,
                    AppConstants.CompanyRoles.Worker => AppConstants.Roles.Employee,
                    _ => AppConstants.Roles.ReadOnly
                };

                await _userManager.AddToRoleAsync(user, legacyRole);

_logger.LogInformation("User {Email} created successfully by {Admin}",
                    user.Email, User.Identity?.Name);

                TempData["Success"] = $"User '{user.FullName}' created successfully.";
                return RedirectToAction(nameof(Index));
            }
            else
            {
                foreach (var error in result.Errors)
                {
                    ModelState.AddModelError("", error.Description);
                }
                return View(model);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error creating user");
            ModelState.AddModelError("", "An error occurred while creating the user.");
            return View(model);
        }
    }

    /// <summary>
    /// Loads the user edit form. Blocks access to platform users (SuperAdmins, identified by
    /// <c>CompanyRole == null</c>) and to users in other companies, even for SuperAdmins who
    /// happen to be visiting via a company context, because cross-company user edits are done
    /// through <c>PlatformUsersController</c>. The optional <paramref name="returnUrl"/> allows
    /// callers such as the Companies/Details view to receive the user back after the edit.
    /// </summary>
    // GET: CompanyUsers/Edit/id
    public async Task<IActionResult> Edit(string id, string? returnUrl = null)
    {
        if (string.IsNullOrEmpty(id))
        {
            return NotFound();
        }

        try
        {
            var companyId = _tenantContext.GetCurrentCompanyId();
            var isSuperAdmin = _tenantContext.IsSuperAdmin();

            if (!companyId.HasValue && !isSuperAdmin)
            {
                TempData["Error"] = "Unable to determine your company.";
                return RedirectToAction(nameof(Index));
            }

            var user = await _userManager.FindByIdAsync(id);

            // SECURITY: Prevent access to platform users (SuperAdmins) and users from other companies
            if (user == null ||
                (!isSuperAdmin && user.CompanyId != companyId!.Value) ||
                user.CompanyRole == null) // CompanyRole == null indicates platform user (SuperAdmin)
            {
                TempData["Error"] = "User not found or access denied.";
                return RedirectToAction(nameof(Index));
            }

            var model = new UpdateCompanyUserDto
            {
                Id = user.Id,
                Email = user.Email ?? "",
                FirstName = user.FirstName,
                LastName = user.LastName,
                EmployeeNumber = user.EmployeeNumber,
                CompanyRole = user.CompanyRole ?? AppConstants.CompanyRoles.Viewer,
                Department = user.Department,
                Position = user.Position,
                LaborCostPerHour = user.LaborCostPerHour,
                Phone = user.PhoneNumber,
                IsActive = user.IsActive,
                HireDate = user.HireDate,
                TerminationDate = user.TerminationDate,
                CanManageJobs = user.CanManageJobs,
                CanManageInventory = user.CanManageInventory,
                CanManageCustomers = user.CanManageCustomers,
                CanCreateQuotes = user.CanCreateQuotes,
                CanApproveQuotes = user.CanApproveQuotes,
                CanManageCalendar = user.CanManageCalendar,
                CanViewCalendar = user.CanViewCalendar,
                CanManageProducts = user.CanManageProducts,
                CanViewProducts = user.CanViewProducts,
                CanManageEquipment = user.CanManageEquipment,
                CanManageVendors = user.CanManageVendors,
                CanManageMaintenance = user.CanManageMaintenance,
                CanManageInvoices = user.CanManageInvoices,
                CanViewReports = user.CanViewReports,
                CanManageBills = user.CanManageBills,
                CanManageAccounting = user.CanManageAccounting
            };

            ViewBag.ReturnUrl = returnUrl;
            ViewBag.IsSuperAdmin = isSuperAdmin;
            return View(model);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error loading user for edit: {UserId}", id);
            TempData["Error"] = "An error occurred while loading the user.";
            return RedirectToAction(nameof(Index));
        }
    }

    /// <summary>
    /// Saves changes to an existing company user. Validates company isolation and role whitelist
    /// (same checks as <see cref="Edit(string, string)"/>). Prevents two dangerous deactivation
    /// scenarios: a user deactivating themselves, and deactivating the last active CompanyAdmin
    /// for a company (which would lock out the tenant). Email changes are applied via
    /// <c>SetEmailAsync</c> / <c>SetUserNameAsync</c> after the main update so Identity's own
    /// normalisation logic runs correctly.
    /// </summary>
    // POST: CompanyUsers/Edit/id
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(string id, UpdateCompanyUserDto model, string? returnUrl = null)
    {
        if (id != model.Id)
        {
            return NotFound();
        }

        if (!ModelState.IsValid)
        {
            ViewBag.ReturnUrl = returnUrl;
            return View(model);
        }

        try
        {
            var companyId = _tenantContext.GetCurrentCompanyId();
            var isSuperAdmin = _tenantContext.IsSuperAdmin();

            if (!companyId.HasValue && !isSuperAdmin)
            {
                TempData["Error"] = "Unable to determine your company.";
                return RedirectToAction(nameof(Index));
            }

            var user = await _userManager.FindByIdAsync(id);

            // SECURITY: Prevent access to platform users (SuperAdmins) and users from other companies
            if (user == null ||
                (!isSuperAdmin && user.CompanyId != companyId!.Value) ||
                user.CompanyRole == null) // CompanyRole == null indicates platform user (SuperAdmin)
            {
                TempData["Error"] = "User not found or access denied.";
                return RedirectToAction(nameof(Index));
            }

            var oldEmail = user.Email ?? string.Empty;
            var emailChanged = !string.Equals(model.Email, oldEmail, StringComparison.OrdinalIgnoreCase);

            // If email is changing, verify the new address isn't already taken
            if (emailChanged)
            {
                var existing = await _userManager.FindByEmailAsync(model.Email);
                if (existing != null)
                {
                    ModelState.AddModelError("Email", "A user with this email already exists.");
                    ViewBag.ReturnUrl = returnUrl;
                    ViewBag.IsSuperAdmin = isSuperAdmin;
                    return View(model);
                }
            }

            // SECURITY: Ensure CompanyRole is a valid company role (prevent elevation to platform user)
            var validCompanyRoles = new[]
            {
                AppConstants.CompanyRoles.CompanyAdmin,
                AppConstants.CompanyRoles.Manager,
                AppConstants.CompanyRoles.Accountant,
                AppConstants.CompanyRoles.Worker,
                AppConstants.CompanyRoles.Viewer
            };

            if (string.IsNullOrWhiteSpace(model.CompanyRole) || !validCompanyRoles.Contains(model.CompanyRole))
            {
                ModelState.AddModelError("CompanyRole", "Invalid company role selected.");
                ViewBag.ReturnUrl = returnUrl;
                return View(model);
            }

            // Company Admins always get all permissions (unless a SuperAdmin is explicitly customizing them)
            var isCompanyAdmin = model.CompanyRole == AppConstants.CompanyRoles.CompanyAdmin;
            var forceAllPermissions = isCompanyAdmin && !isSuperAdmin;

            // Guards when attempting to deactivate an active user
            if (!model.IsActive && user.IsActive)
            {
                // Guard 1: cannot deactivate your own account
                if (user.Id == _userManager.GetUserId(User))
                {
                    ModelState.AddModelError("IsActive", "You cannot deactivate your own account.");
                    ViewBag.ReturnUrl = returnUrl;
                    return View(model);
                }

                // Guard 2: at least one active CompanyAdmin must remain
                if (user.CompanyRole == AppConstants.CompanyRoles.CompanyAdmin)
                {
                    var activeAdminCount = _userManager.Users.Count(u =>
                        u.CompanyId == user.CompanyId &&
                        u.CompanyRole == AppConstants.CompanyRoles.CompanyAdmin &&
                        u.IsActive &&
                        u.Id != user.Id);

                    if (activeAdminCount == 0)
                    {
                        ModelState.AddModelError("IsActive", "Cannot deactivate this user. At least one active Company Admin must remain.");
                        ViewBag.ReturnUrl = returnUrl;
                        return View(model);
                    }
                }
            }

            // Update user properties
            user.FirstName = model.FirstName;
            user.LastName = model.LastName;
            user.EmployeeNumber = model.EmployeeNumber;
            user.CompanyRole = model.CompanyRole;
            user.Department = model.Department;
            user.Position = model.Position;
            user.LaborCostPerHour = model.LaborCostPerHour;
            user.PhoneNumber = model.Phone;
            user.IsActive = model.IsActive;
            user.HireDate = model.HireDate;
            user.TerminationDate = model.TerminationDate;
            // SuperAdmins can set individual permissions even for CompanyAdmin users
            user.CanManageJobs = forceAllPermissions || model.CanManageJobs;
            user.CanManageInventory = forceAllPermissions || model.CanManageInventory;
            user.CanManageCustomers = forceAllPermissions || model.CanManageCustomers;
            user.CanCreateQuotes = forceAllPermissions || model.CanCreateQuotes;
            user.CanApproveQuotes = forceAllPermissions || model.CanApproveQuotes;
            user.CanManageCalendar = forceAllPermissions || model.CanManageCalendar;
            user.CanViewCalendar = forceAllPermissions || model.CanViewCalendar;
            user.CanManageProducts = forceAllPermissions || model.CanManageProducts;
            user.CanViewProducts = forceAllPermissions || model.CanViewProducts;
            user.CanManageEquipment = forceAllPermissions || model.CanManageEquipment;
            user.CanManageVendors = forceAllPermissions || model.CanManageVendors;
            user.CanManageMaintenance = forceAllPermissions || model.CanManageMaintenance;
            user.CanManageInvoices = forceAllPermissions || model.CanManageInvoices;
            user.CanViewReports = forceAllPermissions || model.CanViewReports;
            user.CanManageBills = forceAllPermissions || model.CanManageBills;
            user.CanManageAccounting = forceAllPermissions || model.CanManageAccounting;
            user.UpdatedAt = DateTime.UtcNow;

            var result = await _userManager.UpdateAsync(user);

            if (result.Succeeded)
            {
                // Apply email/username change if requested
                if (emailChanged)
                {
                    await _userManager.SetEmailAsync(user, model.Email);
                    await _userManager.SetUserNameAsync(user, model.Email);
                    _logger.LogInformation("Email changed for user {UserId} from {OldEmail} to {NewEmail} by {Admin}",
                        user.Id, oldEmail, model.Email, User.Identity?.Name);
                }

_logger.LogInformation("User {Email} updated successfully by {Admin}",
                    user.Email, User.Identity?.Name);

                TempData["Success"] = "User updated successfully.";

                // Redirect to returnUrl if provided, otherwise Index
                if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
                {
                    return Redirect(returnUrl);
                }
                return RedirectToAction(nameof(Index));
            }
            else
            {
                foreach (var error in result.Errors)
                {
                    ModelState.AddModelError("", error.Description);
                }
                ViewBag.ReturnUrl = returnUrl;
                ViewBag.IsSuperAdmin = isSuperAdmin;
                return View(model);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error updating user {UserId}", id);
            ModelState.AddModelError("", "An error occurred while updating the user.");
            ViewBag.ReturnUrl = returnUrl;
            return View(model);
        }
    }

    /// <summary>
    /// Toggles a company user's <c>IsActive</c> flag. Applies the same self-deactivation and
    /// last-admin guards as the Edit POST. After the toggle, the referer is inspected to redirect
    /// back to Companies/Details if that's where the request originated, providing a smoother
    /// SuperAdmin workflow. The referer host is validated against the current request host to
    /// prevent open-redirect attacks.
    /// </summary>
    // POST: CompanyUsers/ToggleActive/id
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> ToggleActive(string id)
    {
        try
        {
            var companyId = _tenantContext.GetCurrentCompanyId();
            var isSuperAdmin = _tenantContext.IsSuperAdmin();

            if (!companyId.HasValue && !isSuperAdmin)
            {
                TempData["Error"] = "Unable to determine your company.";
                return RedirectToAction(nameof(Index));
            }

            var user = await _userManager.FindByIdAsync(id);

            // SECURITY: Prevent access to platform users (SuperAdmins) and users from other companies
            if (user == null ||
                (!isSuperAdmin && user.CompanyId != companyId!.Value) ||
                user.CompanyRole == null) // CompanyRole == null indicates platform user (SuperAdmin)
            {
                TempData["Error"] = "User not found or access denied.";
                return RedirectToAction(nameof(Index));
            }

            // Guards only apply when deactivating (not reactivating)
            if (user.IsActive)
            {
                // Guard 1: cannot deactivate your own account
                if (user.Id == _userManager.GetUserId(User))
                {
                    TempData["Error"] = "You cannot deactivate your own account.";
                    return RedirectToAction(nameof(Index));
                }

                // Guard 2: at least one active CompanyAdmin must remain
                if (user.CompanyRole == AppConstants.CompanyRoles.CompanyAdmin)
                {
                    var activeAdminCount = _userManager.Users.Count(u =>
                        u.CompanyId == user.CompanyId &&
                        u.CompanyRole == AppConstants.CompanyRoles.CompanyAdmin &&
                        u.IsActive &&
                        u.Id != user.Id);

                    if (activeAdminCount == 0)
                    {
                        TempData["Error"] = "Cannot deactivate this user. At least one active Company Admin must remain.";
                        return RedirectToAction(nameof(Index));
                    }
                }
            }

            user.IsActive = !user.IsActive;
            user.UpdatedAt = DateTime.UtcNow;

            var result = await _userManager.UpdateAsync(user);

            if (result.Succeeded)
            {
                var status = user.IsActive ? "activated" : "deactivated";
                _logger.LogInformation("User {Email} {Status} by {Admin}",
                    user.Email, status, User.Identity?.Name);

                TempData["Success"] = $"User {status} successfully.";
            }
            else
            {
                TempData["Error"] = "Failed to update user status.";
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error toggling user active status for {UserId}", id);
            TempData["Error"] = "An error occurred while updating the user status.";
        }

        // Redirect back to Companies/Details if that's where the action came from.
        // Validate the referer is same-host to prevent open redirect.
        var referer = Request.Headers["Referer"].ToString();
        if (!string.IsNullOrEmpty(referer)
            && Uri.TryCreate(referer, UriKind.Absolute, out var refUri)
            && string.Equals(refUri.Host, Request.Host.Host, StringComparison.OrdinalIgnoreCase)
            && refUri.AbsolutePath.StartsWith("/Companies/Details/", StringComparison.OrdinalIgnoreCase))
        {
            return LocalRedirect(refUri.PathAndQuery);
        }
        return RedirectToAction(nameof(Index));
    }

    /// <summary>
    /// Bans a company user, preventing all future logins. SuperAdmins can ban any company user;
    /// company admins can ban users within their own company. A ban reason is required.
    /// </summary>
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> BanUser(string id, string reason, string? returnUrl = null)
    {
        try
        {
            var companyId = _tenantContext.GetCurrentCompanyId();
            var isSuperAdmin = _tenantContext.IsSuperAdmin();

            var user = await _userManager.FindByIdAsync(id);
            if (user == null || user.CompanyRole == null ||
                (!isSuperAdmin && user.CompanyId != companyId))
            {
                TempData["Error"] = "User not found or access denied.";
                return Redirect(returnUrl ?? Url.Action(nameof(Index))!);
            }

            if (user.Id == _userManager.GetUserId(User))
            {
                TempData["Error"] = "You cannot ban your own account.";
                return Redirect(returnUrl ?? Url.Action(nameof(Index))!);
            }

            user.IsBanned = true;
            user.BannedAt = DateTime.UtcNow;
            user.BanReason = reason?.Trim();
            user.BannedByUserId = _userManager.GetUserId(User);
            user.UpdatedAt = DateTime.UtcNow;

            var result = await _userManager.UpdateAsync(user);
            if (result.Succeeded)
            {
                _logger.LogWarning("User {Email} banned by {Admin}. Reason: {Reason}", user.Email, User.Identity?.Name, reason);
                TempData["Success"] = $"{user.Email} has been banned.";
            }
            else
            {
                TempData["Error"] = "Failed to ban user.";
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error banning user {UserId}", id);
            TempData["Error"] = "An error occurred.";
        }

        return Redirect(returnUrl ?? Url.Action(nameof(Index))!);
    }

    /// <summary>
    /// Lifts a ban on a company user, restoring their ability to log in.
    /// </summary>
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> UnbanUser(string id, string? returnUrl = null)
    {
        try
        {
            var companyId = _tenantContext.GetCurrentCompanyId();
            var isSuperAdmin = _tenantContext.IsSuperAdmin();

            var user = await _userManager.FindByIdAsync(id);
            if (user == null || user.CompanyRole == null ||
                (!isSuperAdmin && user.CompanyId != companyId))
            {
                TempData["Error"] = "User not found or access denied.";
                return Redirect(returnUrl ?? Url.Action(nameof(Index))!);
            }

            user.IsBanned = false;
            user.BannedAt = null;
            user.BanReason = null;
            user.BannedByUserId = null;
            user.UpdatedAt = DateTime.UtcNow;

            var result = await _userManager.UpdateAsync(user);
            if (result.Succeeded)
            {
                _logger.LogInformation("User {Email} unbanned by {Admin}", user.Email, User.Identity?.Name);
                TempData["Success"] = $"{user.Email} has been unbanned.";
            }
            else
            {
                TempData["Error"] = "Failed to unban user.";
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error unbanning user {UserId}", id);
            TempData["Error"] = "An error occurred.";
        }

        return Redirect(returnUrl ?? Url.Action(nameof(Index))!);
    }

    /// <summary>
    /// Resets the password for a company user. Blocked for platform users (SuperAdmins) and
    /// users belonging to other companies. The old password hash is removed and the new one
    /// set via <c>AddPasswordAsync</c> rather than using a token-based reset flow, as this
    /// is an admin-initiated action rather than a user self-service one. After the operation,
    /// the response respects the referer to redirect back to Companies/Details if applicable.
    /// </summary>
    // POST: CompanyUsers/ResetPassword/id
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> ResetPassword(string id, string newPassword)
    {
        try
        {
            var companyId = _tenantContext.GetCurrentCompanyId();
            var isSuperAdmin = _tenantContext.IsSuperAdmin();

            if (!companyId.HasValue && !isSuperAdmin)
            {
                TempData["Error"] = "Unable to determine your company.";
                return RedirectToAction(nameof(Index));
            }

            var user = await _userManager.FindByIdAsync(id);

            // SECURITY: Prevent access to platform users (SuperAdmins) and users from other companies
            if (user == null ||
                (!isSuperAdmin && user.CompanyId != companyId!.Value) ||
                user.CompanyRole == null) // CompanyRole == null indicates platform user (SuperAdmin)
            {
                TempData["Error"] = "User not found or access denied.";
                return RedirectToAction(nameof(Index));
            }

            // Remove old password
            var removeResult = await _userManager.RemovePasswordAsync(user);
            if (!removeResult.Succeeded)
            {
                TempData["Error"] = "Failed to reset password.";
                return RedirectToAction(nameof(Index));
            }

            // Add new password
            var addResult = await _userManager.AddPasswordAsync(user, newPassword);

            if (addResult.Succeeded)
            {
                _logger.LogInformation("Password reset for user {Email} by {Admin}",
                    user.Email, User.Identity?.Name);

                TempData["Success"] = "Password reset successfully.";
            }
            else
            {
                TempData["Error"] = $"Failed to reset password: {string.Join(", ", addResult.Errors.Select(e => e.Description))}";
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error resetting password for user {UserId}", id);
            TempData["Error"] = "An error occurred while resetting the password.";
        }

        // Redirect back to Companies/Details if that's where the action came from.
        // Validate the referer is same-host to prevent open redirect.
        var referer = Request.Headers["Referer"].ToString();
        if (!string.IsNullOrEmpty(referer)
            && Uri.TryCreate(referer, UriKind.Absolute, out var refUri)
            && string.Equals(refUri.Host, Request.Host.Host, StringComparison.OrdinalIgnoreCase)
            && refUri.AbsolutePath.StartsWith("/Companies/Details/", StringComparison.OrdinalIgnoreCase))
        {
            return LocalRedirect(refUri.PathAndQuery);
        }
        return RedirectToAction(nameof(Index));
    }

    /// <summary>
    /// Generates a password reset link and emails it to the user. Intended for admins who need
    /// to unblock a user who cannot log in (e.g., wrong email at signup, lost password).
    /// Uses ASP.NET Identity's standard token so the user sets their own password via the reset page.
    /// </summary>
    // POST: CompanyUsers/SendPasswordResetEmail/id
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> SendPasswordResetEmail(string id)
    {
        var companyId = _tenantContext.GetCurrentCompanyId();
        var isSuperAdmin = _tenantContext.IsSuperAdmin();

        var user = await _userManager.FindByIdAsync(id);

        if (user == null ||
            (!isSuperAdmin && user.CompanyId != companyId) ||
            user.CompanyRole == null)
        {
            TempData["Error"] = "User not found or access denied.";
            return RedirectToAction(nameof(Index));
        }

        try
        {
            var token = await _userManager.GeneratePasswordResetTokenAsync(user);
            var encodedToken = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(token));
            var resetUrl = $"{Request.Scheme}://{Request.Host}/Identity/Account/ResetPassword" +
                           $"?code={Uri.EscapeDataString(encodedToken)}";

            var firstName = user.FirstName ?? user.Email ?? "there";
            var subject = "Password Reset — Powder Coating Logix";
            var plain =
                $"Hi {firstName},\r\n\r\n" +
                $"A password reset was requested for your Powder Coating Logix account.\r\n\r\n" +
                $"Click the link below to set a new password:\r\n{resetUrl}\r\n\r\n" +
                $"This link expires in 24 hours. If you did not request this, you can safely ignore it.\r\n\r\n" +
                $"— The Powder Coating Logix Team";
            var html =
                $"<p>Hi {System.Net.WebUtility.HtmlEncode(firstName)},</p>" +
                $"<p>A password reset was requested for your Powder Coating Logix account.</p>" +
                $"<p><a href=\"{System.Net.WebUtility.HtmlEncode(resetUrl)}\" " +
                $"style=\"background:#0d6efd;color:#fff;padding:10px 20px;border-radius:4px;" +
                $"text-decoration:none;display:inline-block\">Set New Password</a></p>" +
                $"<p style=\"color:#6c757d;font-size:0.875em\">Or copy this link: {System.Net.WebUtility.HtmlEncode(resetUrl)}</p>" +
                $"<p style=\"color:#6c757d;font-size:0.875em\">This link expires in 24 hours.</p>";

            var (success, error) = await _emailService.SendEmailAsync(
                user.Email!, user.FullName, subject, plain, html);

            if (success)
            {
                _logger.LogInformation("Password reset email sent to {Email} by {Admin}",
                    user.Email, User.Identity?.Name);
                TempData["Success"] = $"Password reset email sent to {user.Email}.";
            }
            else
            {
                _logger.LogWarning("Failed to send password reset email to {Email}: {Error}", user.Email, error);
                TempData["Error"] = "Failed to send email. Please try again or reset the password manually.";
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error sending password reset email for user {UserId}", id);
            TempData["Error"] = "An error occurred while sending the reset email.";
        }

        var referer = Request.Headers["Referer"].ToString();
        if (!string.IsNullOrEmpty(referer)
            && Uri.TryCreate(referer, UriKind.Absolute, out var refUri)
            && string.Equals(refUri.Host, Request.Host.Host, StringComparison.OrdinalIgnoreCase))
        {
            return LocalRedirect(refUri.PathAndQuery);
        }
        return RedirectToAction(nameof(Index));
    }
}
