using BBM.ChatGLM.Dtos;
using Lion.AbpPro.BasicManagement.Roles;
using Lion.AbpPro.BasicManagement.Users;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using NetTopologySuite.Mathematics;
using OfficeOpenXml;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using System.Text.RegularExpressions;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Identity;

namespace BBM.ChatGLM.User
{
    [Authorize]
    public class UsersAppService : ChatGLMAppService, IUsersAppService
    {
        private readonly IdentityUserManager _userManager;
        private readonly IUserAppService _userAppService;
        private readonly UsersManager _usersManager;
        private readonly IRoleAppService _roleAppService;
        private readonly IConfiguration _configuration;
        public UsersAppService(IdentityUserManager userManager, IUserAppService userAppService, UsersManager usersManager, IConfiguration configuration)
        {
            _userManager = userManager;
            _userAppService = userAppService;
            _usersManager = usersManager;
            _configuration = configuration;
        }

        [Authorize(ChatGLMPermissions.UsersManagement.Query)]
        public async Task<PagedResultDto<UserDto>> PageAsync(UserPageInput input)
        {
            var result = new PagedResultDto<UserDto>
            {
                TotalCount = await _usersManager.CountAsync(input.Name, input.Enabled)
            };
            result.Items = await _usersManager.PageAsync(input.Name, input.PageSize, input.PageIndex, input.Enabled);
            return result;
        }

        [Authorize(ChatGLMPermissions.UsersManagement.Create)]
        public async Task<IdentityUserDto> CreateAsync(UserCreateInput input)
        {
            var identityUser = new IdentityUserCreateDto
            {
                UserName = input.UserName,
                Password = input.Password,
                Name = input.Name,
                RoleNames = new string[] { input.Role },
                Email = "zs@baibaomen.com"
            };
            return await _userAppService.CreateAsync(identityUser);
        }

        [Authorize(ChatGLMPermissions.UsersManagement.Update)]
        public async Task<IdentityUserDto> UpdateAsync(UserUpdateInput input)
        {
            var user = await _userManager.GetByIdAsync(input.Id);
            await _userManager.SetRolesAsync(user, new string[] { input.Role });

            var u = await _userManager.FindByIdAsync(input.Id.ToString());
            u.Name = input.Name;
            u.SetIsActive(input.IsActive);
            await _userManager.UpdateAsync(u);

            return ObjectMapper.Map<IdentityUser, IdentityUserDto>(user);
        }

        [Authorize(ChatGLMPermissions.UsersManagement.ResetPassword)]
        public async Task<bool> ResetPasswordAsync(UserResetPasswordInput input)
        {
            var user = await _userManager.GetByIdAsync(input.Id);
            var token = await _userManager.GeneratePasswordResetTokenAsync(user);
            var result = await _userManager.ResetPasswordAsync(user, token, input.Password);
            return result.Succeeded;
        }

        [Authorize(ChatGLMPermissions.UsersManagement.Delete)]
        public async Task<bool> DeleteAsync(GuidIdInput input)
        {
            var user = await _userManager.FindByIdAsync(input.Id.ToString());
            if (user == null)
            {
                return false;
            }
            user.IsDeleted = true;
            var result = await _userManager.UpdateAsync(user);
            return result.Succeeded;
        }

        [Authorize(ChatGLMPermissions.UsersManagement.Query)]
        public async Task<List<string>> GetRolesAsync()
        {
            var user = CurrentUser.Name;
            var roles = await _usersManager.GetRolesAsync();
            return roles.WhereIf(user == "admin", item => item.Name != "admin").Select(role => role.Name).ToList();
        }

        [Authorize(ChatGLMPermissions.UsersManagement.Chat)]
        public async Task<string> GetTokenAsync()
        {
            var client = new HttpClient();
            var apiKey = _configuration.GetValue<string>("App:ApiKey");
            var url = $"https://glm-api.baibaomen.com/token?appkey={apiKey}";
            try
            {
                var response = await client.GetAsync(url);
                if (response.IsSuccessStatusCode)
                {
                    var content = await response.Content.ReadAsStringAsync();
                    var data = JsonSerializer.Deserialize<TokenObject>(content);
                    return data.token;
                }
                else
                {
                    throw new BusinessException("BBM.ChatGLM:100012");
                }
            }
            catch
            {
                throw new BusinessException("BBM.ChatGLM:100012");
            }
        }



        [Authorize(ChatGLMPermissions.UsersManagement.Create)]
        public async Task<ImportUsersResult> CreateUsersByExcel([FromForm] IFormFile file)
        {
            /**
             * [FromForm] 
             *  操作步骤
             *      1、React中，使用antd的Upload组件来上传Excel表格数据，并且在上传之前需要将表格数据转换成FormData。
             *      2、在ASP.NET中，建立一个Controller用于接收上传的文件，并且使用[HttpPost]属性来指定使用POST方法接收请求。
             *      3、在Controller中，使用IFormFile接口来接收上传的Excel文件，然后使用EPPlus等工具来读取Excel文件数据
             *      4、将读取到的Excel数据进行处理，例如存储到数据库中或者进行数据分析等操作
             */

            List<Dtos.Results> results = new List<Dtos.Results>();
            Dtos.Results xiangying = new Dtos.Results();
            var failNum = 0;

            if (file == null)
            {
                xiangying = FailReason("", "", "", "", "Excel文件为空");
                results.Add(xiangying);
                return new ImportUsersResult
                {
                    Results = new List<Dtos.Results> { },
                    FailNum = 0,
                    SuccessNum = 0
                };
            }

            string directoryPath = Environment.CurrentDirectory + @"\Excels";
            if (!Directory.Exists(directoryPath))
                Directory.CreateDirectory(directoryPath);

            var filePath = Path.Combine(directoryPath, file.FileName);

            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                await file.CopyToAsync(stream);
            }

            using (var package = new ExcelPackage(new FileInfo(filePath)))
            {
                var worksheet = package.Workbook.Worksheets["sheet1"];
                var totalRows = worksheet.Dimension.Rows;
                var row = 2;


                var userName = "";
                var phoneNumber = "";
                var userRole = "";
                var noData = false;

                while (row <= totalRows)
                {
                    try
                    {
                        userName = worksheet.Cells[row, 1].Value?.ToString().Replace(" ", "") ?? "";
                        phoneNumber = worksheet.Cells[row, 2].Value?.ToString().Replace(" ", "") ?? "";
                        userRole = worksheet.Cells[row, 3].Value?.ToString().Replace(" ", "") ?? "";

                        userName = Regex.Replace(userName, @"\s", "");
                        phoneNumber = Regex.Replace(phoneNumber, @"\s", "");
                        userRole = Regex.Replace(userRole, @"\s", "");

                        if (totalRows == 2 && string.IsNullOrEmpty(userName) && string.IsNullOrEmpty(phoneNumber) && string.IsNullOrEmpty(userRole))
                        {
                            noData = true;
                            continue;
                        }

                        if (string.IsNullOrEmpty(userName))
                        {
                            failNum++;
                            xiangying = FailReason(userName, phoneNumber, userRole, "失败", "用户名不正确");
                        }
                        else if (userName.Length > 20)
                        {
                            failNum++;
                            xiangying = FailReason(userName, phoneNumber, userRole, "失败", "用户名超出长度限制");
                        }
                        else if (!Regex.IsMatch(userName, @"^[\u4e00-\u9fa5a-zA-Z]+$"))
                        {
                            failNum++;
                            xiangying = FailReason(userName, phoneNumber, userRole, "失败", "用户名包含特殊符号");
                        }

                        else if (string.IsNullOrEmpty(phoneNumber))
                        {
                            failNum++;
                            xiangying = FailReason(userName, phoneNumber, userRole, "失败", "手机号码不正确");
                        }

                        else if (!Regex.IsMatch(phoneNumber, @"^(133|153|189|180|181|177|173|199|174|141|
                                    |139|138|137|136|135|134|159|158|157|150|151|152|147|188|187|182|183|184|178|198|
                                    |130|131|132|146|156|155|166|186|185|145|175|176|
                                    |170|171|123)\d{8}$"))
                        {
                            failNum++;
                            xiangying = FailReason(userName, phoneNumber, userRole, "失败", "手机号码格式不正确");
                        }
                        else if (phoneNumber.Length > 11)
                        {
                            failNum++;
                            xiangying = FailReason(userName, phoneNumber, userRole, "失败", "手机号码超出长度限制");
                        }
                        else if (userRole != "普通用户" && userRole != "管理员")
                        {
                            failNum++;
                            xiangying = FailReason(userName, phoneNumber, userRole, "失败", "角色输入不正确");
                        }
                        else
                        {
                            var password = "Zs" + phoneNumber.Substring(phoneNumber.Length - 6);
                            if (userRole == "管理员")
                            {
                                userRole = "admin";
                            }

                            UserCreateInput userInput = new UserCreateInput();
                            userInput.Name = userName;
                            userInput.UserName = phoneNumber;
                            userInput.Password = password;
                            userInput.Role = userRole;
                            userInput.IsActive = true;

                            var res = await CreateAsync(userInput);
                            xiangying = FailReason(userName, phoneNumber, userRole, "成功", "");
                        }
                    }
                    catch (Exception ex)
                    {
                        failNum++;
                        xiangying = FailReason(userName, phoneNumber, userRole, "失败", "已存在当前用户,重复添加失败");
                    }
                    finally
                    {
                        row++;
                        results.Add(xiangying);
                    }
                }

                return new ImportUsersResult
                {
                    Results = results,
                    FailNum = failNum,
                    SuccessNum = noData ? 0 : (totalRows - 1) - failNum
                };
            }
        }

        public Dtos.Results FailReason(string userName, string phone, string role, string state, string reason)
        {
            Dtos.Results results = new Dtos.Results();
            results.userName = userName;
            results.phone = phone;
            results.role = role;
            results.state = state;
            results.failureReason = reason;
            return results;
        }
    }
}
