using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PSTW_CentralSystem.DBContext;
using PSTW_CentralSystem.Models;
using System.Reflection;
using static System.Runtime.InteropServices.JavaScript.JSType;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.ComponentModel.DataAnnotations;
using PSTW_CentralSystem.Areas.Inventory.Models;
using System.Security.Cryptography.X509Certificates;

namespace PSTW_CentralSystem.Controllers.API
{
    [ApiController]
    [Route("[controller]")]

    public class AdminAPI : Controller
    {
        private readonly ILogger<AdminAPI> _logger;
        private readonly CentralSystemContext _centralDbContext;
        private readonly UserManager<UserModel> _userManager;
        private readonly SignInManager<UserModel> _signInManager;
        private readonly RoleManager<RoleModel> _roleManager;

        public AdminAPI(ILogger<AdminAPI> logger, CentralSystemContext authDbContext, UserManager<UserModel> userManager, SignInManager<UserModel> signInManager, RoleManager<RoleModel> roleManager)
        {
            _logger = logger;
            _centralDbContext = authDbContext;
            _userManager = userManager;
            _signInManager = signInManager;
            _roleManager = roleManager;
        }

        [HttpPost("GetClassAndMethodInformation")]
        public async Task<IActionResult> GetClassAndMethodInformation(string moduleName)
        {
            var controllerAndMethodList = new object();

            // Get the assembly containing the controllers
            var assembly = Assembly.GetExecutingAssembly();

            // Get all types in the assembly (controllers will typically be in the "Controllers" namespace)
            //var controllerTypes = await Task.Run(() => assembly.GetTypes().Where(type => typeof(ControllerBase).IsAssignableFrom(type) && type.IsClass && type.CompanyName.Contains("Controller") && type.CompanyName != "AdminController") .ToList());
            var controllerTypes = await Task.Run(() => assembly.GetTypes().Where(type => typeof(ControllerBase).IsAssignableFrom(type) && !type.Name.Contains("API") && type.IsClass && type.Name.Contains(moduleName)).FirstOrDefault());

            // Iterate over the controller types and get their methods
                var methods = controllerTypes?.GetMethods(BindingFlags.Public | BindingFlags.Instance)
                    .Where(m => m.DeclaringType == controllerTypes) // Filter methods declared directly in the controller (ignoring inherited ones)
                    .Select(m => m.Name) // Get the method names
                    .ToList();

                controllerAndMethodList = (new
                {
                    Controller = controllerTypes?.Name,
                    Methods = methods
                });

            // Return the list as JSON
            return Json(controllerAndMethodList);
        }

        [HttpPost("GetListClassAndMethodInformation")]
        public async Task<IActionResult> GetListClassAndMethodInformation()
        {
            var controllerAndMethodList = new List<object>();

            // Get the assembly containing the controllers
            var assembly = Assembly.GetExecutingAssembly();

            // Get all types in the assembly (controllers will typically be in the "Controllers" namespace)
            //var controllerTypes = await Task.Run(() => assembly.GetTypes().Where(type => typeof(ControllerBase).IsAssignableFrom(type) && type.IsClass && type.CompanyName.Contains("Controller") && type.CompanyName != "AdminController") .ToList());
            var controllerTypes = await Task.Run(() => assembly.GetTypes().Where(type => typeof(ControllerBase).IsAssignableFrom(type) && type.IsClass && !type.Name.Contains("API") && !type.Name.Contains("Admin")).ToList());

            // Iterate over the controller types and get their methods
            foreach (var controllerType in controllerTypes) {

                // Get the [Area] attribute, if it exists
                var areaAttribute = controllerType.GetCustomAttributes(true)
                    .OfType<AreaAttribute>()
                    .FirstOrDefault();

                var areaName = areaAttribute?.RouteValue ?? null;

                var methods = controllerType?.GetMethods(BindingFlags.Public | BindingFlags.Instance)
                    .Where(m => m.DeclaringType == controllerType) // Filter methods declared directly in the controller (ignoring inherited ones)
                    .Select(m => m.Name) // Get the method names
                    .ToList();
            
            controllerAndMethodList.Add(new
                {
                    Module = areaName,
                    Controller = controllerType?.Name.Replace("Controller", string.Empty),
                    Methods = methods
                });
            }
            // Return the list as JSON
            return Json(controllerAndMethodList);
        }

        [HttpPost("GetUserList")]
        public async Task<IActionResult> GetUserList()
        {
            try
            {
                var user = await _userManager.GetUserAsync(User);

                var userRole = await _userManager.GetRolesAsync(user??new UserModel());
                List<UserModel> userInfo = new List<UserModel>();

                    // Fetch all users excluding those with roles SuperAdmin or SystemAdmin
                    var allUsers = await _centralDbContext.Users
                        .Include(u => u.Department!.Company)
                        .ToListAsync();

                if (userRole == null || userRole.Count == 0)
                {
                    foreach (var u in allUsers)
                    {
                        var roles = await _userManager.GetRolesAsync(u);
                        if (!roles.Contains("SuperAdmin") && !roles.Contains("SystemAdmin"))
                        {
                            userInfo.Add(u);
                        }
                    }
                }
                else 
                {
                    userInfo = allUsers;
                }
                var userList = userInfo.Select(u => new 
                { 
                    id = u.Id, 
                    email = u.NormalizedEmail, 
                    company = u.Department?.Company?.CompanyName, 
                    department = u.Department?.DepartmentName,
                    role = _userManager.GetRolesAsync(u).Result,
                    status = u.UserInfoStatus,
                }).ToList();
                return Ok(new { UserInfo = userList });
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"An error occurred: {ex.Message}");
            }
        }

        [HttpPatch("UpdateUserStatusAndRole/{id}")]
        public async Task<IActionResult> UpdateUserStatusAndRole(int id, [FromBody] string role)
        {
            try
            {
                var user = await _centralDbContext.Users.Include("Department").FirstOrDefaultAsync(u => u.Id == id);

                if (user == null)
                {
                    return NotFound(new { message = "User not found" });
                }

                var existingUserRoles = await _userManager.GetRolesAsync(user);
                if (existingUserRoles != null && existingUserRoles.Count > 0) { 
                    await _userManager.RemoveFromRolesAsync(user, existingUserRoles);
                }

                await _userManager.AddToRoleAsync(user, role);

                user.UserInfoStatus = 1;
                if (role == "Inventory Master") {
                    var StoreName = user.Department!.DepartmentName + " (" + user.Department!.DepartmentCode + ")";

                    var existingStore = await _centralDbContext.Stores.FirstOrDefaultAsync(s => s.StoreName == StoreName);
                    if (existingStore == null)
                    {
                        existingStore = new StoreModel
                        {
                            StoreName = StoreName,
                            CompanyId = user.Department.CompanyId,
                        };

                        await _centralDbContext.Stores.AddAsync(existingStore);
                        await _centralDbContext.SaveChangesAsync();
                    }

                    var masterStore = await _centralDbContext.Stores.FirstOrDefaultAsync(s => s.Id == existingStore.Id);
                    var newInventoryMaster = new InventoryMasterModel
                    {
                        UserId = user.Id,
                        StoreId = existingStore.Id,
                    };
                    await _centralDbContext.InventoryMasters.AddAsync(newInventoryMaster);
                }
                await _centralDbContext.SaveChangesAsync();

                return Ok(new { message = "User updated successfully" });
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"An error occurred: {ex.Message}");
            }
        }

        [HttpPost("GetDepartmentWithCompanyList")]
        public async Task<IActionResult> GetDepartmentWithCompanyList()
        {
            var companyList = await _centralDbContext.Companies
                .Include(c => c.Departments)
                .Select(c => new {
                    c.CompanyId,
                    c.CompanyName,
                    Departments = c.Departments!
                    .OrderBy(d => d.DepartmentId)
                    .Select(d => new { d.DepartmentId, d.DepartmentName, d.DepartmentCode })
                })
                .ToListAsync();
            return Json(companyList);
        }

        [HttpPost("GetDepartmentWithCompany")]
        public async Task<DepartmentCompany> GetDepartmentWithCompany(int companyId, int departmentId)
        {
            var departmentList = await _centralDbContext.Departments.FirstOrDefaultAsync(d => d.DepartmentId == departmentId);
            var companyList = await _centralDbContext.Companies.FirstOrDefaultAsync(c => c.CompanyId == companyId);

            // Create a new list to store departments with their company name
            var departmentWithCompany = new DepartmentCompany
            {
                DepartmentId = departmentList!.DepartmentId,
                DepartmentName = departmentList.DepartmentName,
                CompanyId = departmentList.CompanyId,
                CompanyName = companyList?.CompanyName,
            };

            // Return the constructed list as JSON
            return departmentWithCompany;
        }

        [HttpPost("AddCompanyDepartment")]
        public async Task<IActionResult> AddCompanyDepartment([FromBody] UpdateDepartmentCompany departmentCompanyDetails)
        {
            try 
            { 
                CompanyModel companyModel = new CompanyModel
                {
                    CompanyName = departmentCompanyDetails.Company!
                };

                _centralDbContext.Companies.Add(companyModel);
                await _centralDbContext.SaveChangesAsync();

                foreach (var department in departmentCompanyDetails.Department!)
                {
                    DepartmentModel departmentModel = new DepartmentModel
                    {
                        CompanyId = companyModel.CompanyId,
                        DepartmentName = department.DepartmentName ?? string.Empty,
                        DepartmentCode = department.DepartmentCode ?? string.Empty
                    };

                    _centralDbContext.Departments.Add(departmentModel);
                    await _centralDbContext.SaveChangesAsync();
                }

                return Ok( new { message = "Company and department added successfully" });
            }
            catch (Exception ex)
            {
                return StatusCode(500, new { message = $"An error occurred: {ex.Message}" });
            }
        }

        public class UpdateDepartmentCompany
        {
            [Required]
            public string? Company { get; set; }
            [Required]
            public List<DepartmentInfo>? Department { get; set; }
            
        }
        public class DepartmentInfo
        {
            [Required]
            public string? DepartmentName { get; set; }
            [Required]
            public string? DepartmentCode { get; set; }
        }
        public class DepartmentCompany
        {
            public int DepartmentId { get; set; }
            public string? DepartmentName { get; set; }
            public int CompanyId { get; set; }
            public string? CompanyName { get; set; }
        }
    }
}
