using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Wordprocessing;
using Infrastructure;
using Infrastructure.Extensions;
using Infrastructure.Helpers;
using Infrastructure.Utilities;
using Microsoft.AspNetCore.Http;
using NetModular.DocX.Core;
using NPOI.HSSF.UserModel;
using NPOI.SS.Formula.Functions;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using OpenAuth.App.Base;
using OpenAuth.App.BaseApp.Base;
using OpenAuth.App.Config;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.App.Response;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using SixLabors.ImageSharp;
using SqlSugar;
using Yitter.IdGenerator;
using static ICSharpCode.SharpZipLib.Zip.ExtendedUnixData;

namespace OpenAuth.App
{
    public class UserManagerApp : SqlSugarBaseApp<SysUser, SugarDbContext>
    {
        private ISqlSugarClient client;

        #region 构造函数
        public UserManagerApp(
            ISugarUnitOfWork<SugarDbContext> unitWork,
            ISimpleClient<SysUser> repository,
            IAuth auth,
            ISqlSugarClient sqlSugarClient
            ) : base(unitWork, repository, auth)
        {
            this.client = sqlSugarClient;
        }
        #endregion

        #region 用户查询

        public async Task<Response<PageInfo<List<dynamic>>>> LoadAll(QueryUserListReq request)
        {
            RefAsync<int> totalNumber = 0;
            //过滤orgid传参
            List<long> dpt = new List<long>();
            if (request.orgId != 0)
            {
                dpt = client.Queryable<SysOrg>().ToChildList(it => it.ParentId, request.orgId)?.Select(it => it.Id).ToList();
            }
            var aa = client.Queryable<SysUserOrg>().Where(r => dpt.Contains(r.OrgId)).ToList();
            var table = await base.Repository.AsQueryable()
                     .WhereIF(!string.IsNullOrEmpty(request.key), u => u.Account.Contains(request.key) || u.Name.Contains(request.key))
                     .LeftJoin<SysUserOrg>((u, o) => u.Id == o.UserId)
                     .WhereIF(request.orgId != 0, (u, o) => dpt.Contains(o.OrgId))
                     .OrderByDescending((u, o) => u.CreateTime)
                     .Distinct()
                     .Select<dynamic>((u, o) => new
                     {
                         id = u.Id,
                         account = u.Account,
                         name = u.Name,
                         createtime = u.CreateTime,
                         department = SqlFunc.Subqueryable<SysUserOrg>().Where(a => a.UserId == u.Id).LeftJoin<SysOrg>((a, o) => a.OrgId == o.Id).SelectStringJoin((a, o) => o.Name, ","),
                         role = SqlFunc.Subqueryable<SysUserRole>().Where(a => a.UserId == u.Id).LeftJoin<SysRole>((a, o) => a.RoleId == o.Id).SelectStringJoin((a, o) => o.Name, ","),
                     })
                     .ToPageListAsync(request.page, request.limit, totalNumber);

            return new Response<PageInfo<List<dynamic>>>()
            {
                Result = new PageInfo<List<dynamic>>
                {
                    Items = table,
                    Total = totalNumber
                }
            };
        }
        public List<long> getAllChildOrgId(long parentId)
        {
            var query = base.Repository.AsSugarClient().Queryable<SysOrg>()
                       .Where(c => c.ParentId == parentId)
                       .Select(c => new { c.Id, c.ParentId })
                       .ToList();

            var childIds = query.Select(c => c.Id).ToList();
            var grandChildIds = query.SelectMany(c => getAllChildOrgId(c.Id)).ToList();

            childIds.AddRange(grandChildIds);
            return childIds;
        }


        public async Task<Response<PageInfo<List<UserView>>>> Load(QueryUserListReq request)
        {

            var user = _auth.GetCurrentUser().User;

            string sqlstr = "select \"min\"(\"Level\") from sys_userorg  where \"UserId\"='" + user.Id + "' ";
            var level = client.Ado.GetInt(sqlstr);
            if (level == 0 || user.Id == -1)
            {


                RefAsync<int> totalNumber = 0;

                var table = await base.Repository.AsQueryable()
                         .WhereIF(!string.IsNullOrEmpty(request.key), u => u.Account.Contains(request.key) || u.Name.Contains(request.key))
                         .WhereIF(request.orgId != 0,
                                  u => SqlFunc.Subqueryable<SysUserOrg>().Where(uo => uo.OrgId == request.orgId && uo.UserId == u.Id).Any())
                         .OrderByDescending(u => u.CreateTime)
                         .Select<UserView>()
                         .ToPageListAsync(request.page, request.limit, totalNumber);

                return new Response<PageInfo<List<UserView>>>()
                {
                    Result = new PageInfo<List<UserView>>
                    {
                        Items = table,
                        Total = totalNumber
                    }
                };


            }
            else
            {
                string sqlstr1 = "select \"OrgId\" from sys_userorg where \"Level\"=" + level + " and \"UserId\"='" + user.Id + "' ";
                List<long> orgIds1 = client.Ado.SqlQuery<long>(sqlstr1);
                int count11 = orgIds1.Count;
                for (int i = 0; i < count11; i++)

                {
                    List<long> longs = getAllChildOrgId(orgIds1[i]);
                    orgIds1.AddRange(longs);
                }
                string keyword = "";
                if (!string.IsNullOrEmpty(request.key))
                {
                    keyword = keyword + "and a.\"Name\" like '%" + request.key + "%'";
                }
                string orgsql = "";
                if (request.orgId != 0)
                {
                    orgsql = " and \"OrgId\" ='" + request.orgId + "'";
                }
                string orgIds = "";
                for (int j = 0; j < orgIds1.Count; j++)
                {
                    if (j == orgIds1.Count - 1)
                    {
                        orgIds = orgIds + orgIds1[j];
                    }
                    else
                    {
                        orgIds = orgIds + orgIds1[j] + ",";
                    }

                }

                string sql = "WITH t as (\r\nselect \"UserId\" from ( select * from sys_userorg where \"UserId\" not in (select \"UserId\" from sys_userorg where \"Level\"<(select \"min\"(\"Level\") from sys_userorg " +
                // " where \"UserId\"='"+ user.Id+ "' ))) a where a.\"OrgId\" in (select \"OrgId\" from sys_userorg where \"UserId\"='"+ user.Id+ "'"+ orgsql + " ) GROUP BY \"UserId\")";
                " where \"UserId\"='" + user.Id + "' ))) a where a.\"OrgId\" =ANY(array[" + orgIds + "])  GROUP BY \"UserId\")";
                string sql1 = "((SELECT a.* FROM t LEFT JOIN sys_user a  on t.\"UserId\"=a.\"Id\"  where 1=1  " + keyword + "   ) UNION (SELECT * FROM sys_user a where a.\"CreateId\"='" + user.Id + "' " + keyword + ")) limit " + request.limit + "OFFSET " + (request.page - 1) * request.limit;
                string sql2 = "(SELECT COUNT(a.*) FROM t LEFT JOIN sys_user a  on t.\"UserId\"=a.\"Id\"  where 1=1  " + keyword + "   )  ";
                string sql3 = "SELECT COUNT(a.*) FROM sys_user a where a.\"CreateId\"='" + user.Id + "' " + keyword;


                var table = client.Ado.SqlQuery<UserView>(sql + sql1);
                int count1 = client.Ado.GetInt(sql + sql2);
                int count2 = client.Ado.GetInt(sql + sql3);

                int count = count1 + count2;
                /*   var orgIds = base._auth.GetCurrentUser().Orgs.Select(o => o.Id);

                   RefAsync<int> totalNumber = 0;

                   var table = await base.Repository.AsQueryable()
                            .WhereIF(!string.IsNullOrEmpty(request.key), u => u.Account.Contains(request.key) || u.Name.Contains(request.key))
                            .WhereIF(request.orgId != 0,
                                     u => SqlFunc.Subqueryable<SysUserOrg>().Where(uo => uo.OrgId == request.orgId && uo.UserId == u.Id).Any())
                            .Where(u => SqlFunc.Subqueryable<SysUserOrg>().Where(uo => orgIds.Contains(uo.OrgId) && uo.UserId == u.Id).Any())
                            .OrderByDescending(u => u.CreateTime)
                            .Select<UserView>()
                            .ToPageListAsync(request.page, request.limit, totalNumber);*/

                return new Response<PageInfo<List<UserView>>>()
                {
                    Result = new PageInfo<List<UserView>>
                    {
                        Items = table,
                        Total = count
                    }
                };
            }
        }

        public async Task<Response<PageInfo<List<dynamic>>>> LoadUsers(QueryUserListReq request)
        {
            //获取当前用户
            var user = _auth.GetCurrentUser().User;
            RefAsync<int> totalNumber = 0;
            //该用户下包含所有部门
            List<long> deplist = new List<long>();
            if (user != null)
            {
                var departs = client.Queryable<SysUserOrg>().Where(r => r.UserId == user.Id).ToList();
                foreach (var item in departs)
                {
                    var list = client.Queryable<SysOrg>().ToChildList(it => it.ParentId, item.OrgId)?.Select(it => it.Id).ToList();
                    deplist = deplist.Union(list).ToList();
                }
            }

            //过滤orgid传参
            List<long> dpt = new List<long>();
            if (request.orgId != 0)
            {
                dpt = client.Queryable<SysOrg>().ToChildList(it => it.ParentId, request.orgId)?.Select(it => it.Id).ToList();
            }

            //获取列表数据
            var table = await base.Repository.AsQueryable()
                 .WhereIF(!string.IsNullOrEmpty(request.key), u => u.Account.Contains(request.key) || u.Name.Contains(request.key))//过滤key
                .LeftJoin<SysUserOrg>((u, o) => u.Id == o.UserId)
                .Where((u, o) => deplist.Contains(o.OrgId) || u.CreateId == user.Id)  //部门及创建人
                .WhereIF(request.orgId != 0, (u, o) => dpt.Contains(o.OrgId)) //部门及左侧选择部门
                .Distinct()
                 .OrderByDescending((u, o) => u.CreateTime)
                 .Select<dynamic>((u, o) => new
                 {
                     id = u.Id,
                     account = u.Account,
                     name = u.Name,
                     create = u.CreateTime,
                     department = SqlFunc.Subqueryable<SysUserOrg>().Where(a => a.UserId == u.Id).LeftJoin<SysOrg>((a, o) => a.OrgId == o.Id).SelectStringJoin((a, o) => o.Name, ","),
                     role = SqlFunc.Subqueryable<SysUserRole>().Where(a => a.UserId == u.Id).LeftJoin<SysRole>((a, o) => a.RoleId == o.Id).SelectStringJoin((a, o) => o.Name, ","),
                 })
                 .ToPageListAsync(request.page, request.limit, totalNumber);

            return new Response<PageInfo<List<dynamic>>>()
            {
                Result = new PageInfo<List<dynamic>>
                {
                    Items = table,
                    Total = totalNumber
                }
            };
        }

        /// <summary>
        /// 获取指定角色包含的用户列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<Response<PageInfo<List<UserView>>>> LoadByRole(QueryUserListByRoleReq request)
        {
            RefAsync<int> totalCount = 0;

            var users = await client.Queryable<SysUserRole>()
                  .LeftJoin<SysUser>((ur, u) => ur.UserId == u.Id)
                  .Where(ur => ur.RoleId == request.roleId)
                  .Select((ur, u) => new UserView
                  {
                      Id = u.Id,
                      Account = u.Account,
                      Name = u.Name
                  }).ToPageListAsync(request.page, request.limit, totalCount);

            return new Response<PageInfo<List<UserView>>>
            {
                Code = 200,
                Message = "success",
                Result = new PageInfo<List<UserView>>
                {
                    Items = users,
                    Total = totalCount
                }
            };

        }


        /// <summary>
        /// 获取指定机构包含的用户列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<TableData> LoadByOrg(QueryUserListByOrgReq request)
        {
            var db = base.Repository.AsSugarClient();
            RefAsync<int> totalCount = 0;

            var users = await db.CopyNew().Queryable<SysUserOrg>()
                .LeftJoin<SysUser>((uo, u) => uo.UserId == u.Id)
                .Where((uo, u) => uo.OrgId == request.orgId)
                .ToPageListAsync(request.page, request.limit, totalCount);

            return new TableData
            {
                count = (int)totalCount,
                data = users
            };
        }

        /// <summary>
        /// 根据 account 判断帐号是否存在
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        public bool IsExistUser(string account)
        {
            return base.Repository.IsAny(a => a.Account == account);
        }

        public SysUser Get(long id)
        {
            return Repository.GetById(id);
        }

        public SysUser GetByAccount(string account)
        {
            return Repository.GetFirst(u => u.Account == account);
        }
        #endregion

        #region 用户增删改

        #region 添加/修改
        public Response<bool> AddOrUpdate(UpdateUserReq request)
        {
            request.ValidationEntity(u => new { u.Account, u.Name });

            SysUser requser = request;
            requser.CreateId = _auth.GetCurrentUser().User.Id;

            using (var uow = base.UnitWork.CreateContext())
            {
                if (request.Id == 0)
                {
                    if (uow.User.IsAny(u => u.Account == request.Account))
                    {
                        throw new Exception("用户账号已存在");
                    }

                    requser.Secretkey = Md5Helper.Encrypt(CommonHelper.CreateNo(), 16).ToLower();
                    if (string.IsNullOrEmpty(requser.Password))
                    {
                        requser.Password = Md5Helper.Encrypt(DESEncrypt.Encrypt(Md5Helper.Hash(requser.Account), requser.Secretkey).ToLower(), 32).ToLower();   //如果客户端没提供密码，默认密码同账号
                    }
                    else
                    {
                        requser.Password = Md5Helper.Encrypt(DESEncrypt.Encrypt(requser.Password, requser.Secretkey).ToLower(), 32).ToLower();
                    }
                    requser.CreateTime = DateTime.Now;
                    requser.Id = Yitter.IdGenerator.YitIdHelper.NextId();
                    uow.User.Insert(requser);
                    request.Id = requser.Id; //要把保存后的ID存入view
                }
                else
                {
                    uow.User.Update(u => new SysUser
                    {
                        Account = requser.Account,
                        BizCode = requser.BizCode,
                        Name = requser.Name,
                        Sex = requser.Sex,
                        Status = requser.Status
                    }, u => u.Id == request.Id);
                    if (!string.IsNullOrEmpty(requser.Password))  //密码为空的时候，不做修改
                    {
                        var userInfo = uow.User.GetById(requser.Id);

                        requser.Password = Md5Helper.Encrypt(DESEncrypt.Encrypt(requser.Password, userInfo.Secretkey).ToLower(), 32).ToLower();
                        uow.User.Update(u => new SysUser
                        {
                            Password = requser.Password
                        }, u => u.Id == request.Id);
                    }
                }

                var flag = uow.Commit();

                return new Response<bool>
                {
                    Result = flag,
                    Message = flag == true ? "success" : "error"
                };
            }
        }
        #endregion

        #region 删除
        /// <summary>
        /// 删除用户,包含用户与组织关系、用户与角色关系
        /// </summary>
        /// <param name="ids"></param>
        public Response<bool> Delete(long[] ids)
        {
            using (var uow = base.UnitWork.CreateContext())
            {
                uow.SysUserOrg.Delete(a => ids.Contains(a.UserId));
                uow.SysUserRole.Delete(a => ids.Contains(a.UserId));
                uow.User.Delete(u => ids.Contains(u.Id));
                var flag = uow.Commit();
                return new Response<bool>
                {
                    Result = flag,
                    Message = flag == true ? "success" : "error"
                };
            }
        }
        #endregion

        #region 分配角色
        public async Task<Response<bool>> UserRoles(AssignUserRoles userRoles)
        {
            using (var uow = base.UnitWork.CreateContext())
            {
                //删除用户相关角色
                await uow.SysUserRole.DeleteByIdAsync(userRoles.UserId);
                //重新添加本次角色
                var models = userRoles.RoleIds.Select(r => new SysUserRole { UserId = userRoles.UserId, RoleId = r }).ToList();
                await uow.SysUserRole.InsertRangeAsync(models);

                var flag = uow.Commit();

                return new Response<bool>
                {
                    Result = flag,
                    Message = flag == true ? "success" : "error"
                };
            }
        }
        #endregion

        #region 分配部门
        public async Task<Response<bool>> UserOrgs(AssignUserOrgs userOrgs)
        {
            using (var uow = base.UnitWork.CreateContext())
            {
                //删除用户相关部门
                await uow.SysUserOrg.DeleteByIdAsync(userOrgs.UserId);
                //重新添加本次部门
                var models = userOrgs.OrgPoses.Select(o => new SysUserOrg { UserId = userOrgs.UserId, OrgId = o.OrgId, PositionId = o.PosId, Level = o.Level }).ToList();
                await uow.SysUserOrg.InsertRangeAsync(models);

                var flag = uow.Commit();

                return new Response<bool>
                {
                    Result = flag,
                    Message = flag == true ? "success" : "error"
                };
            }
        }
        #endregion
        #region 修改密码
        /// <summary>
        /// 修改密码
        /// </summary>
        /// <param name="request"></param>
        public void ChangePassword(ChangePasswordReq request)
        {
            var user = base.Repository.GetFirst(a => a.Account == request.Account);

            if (user != null)
            {
                var pwd = Md5Helper.Encrypt(DESEncrypt.Encrypt(request.Password, user.Secretkey).ToLower(), 32).ToLower();

                Repository.Update(user => new SysUser
                {
                    Password = pwd
                }, u => u.Account == request.Account);
            }
        }
        #endregion

        #region 修改用户资料
        /// <summary>
        /// 修改用户资料
        /// </summary>
        /// <param name="request"></param>
        public void ChangeProfile(ChangeProfileReq request)
        {
            if (request.Account == Define.SYSTEM_USERNAME)
            {
                throw new Exception("不能修改超级管理员信息");
            }

            Repository.Update(user => new SysUser
            {
                Name = request.Name,
                Sex = request.Sex
            }, u => u.Account == request.Account);
        }
        #endregion

        #region 更新数据库实体类
        /// <summary>
        /// 更新数据库实体类
        /// </summary>
        /// <returns></returns>
        public string AddEntity()
        {
            using (var uow = base.UnitWork.CreateContext())
            {
                foreach (var item in uow.Db.DbMaintenance.GetTableInfoList().Where(r => r.Name.ToLower().StartsWith("lasa_annotation")))
                {
                    //string entityName = item.Name.Substring(0, 1).ToUpper() + item.Name.Substring(1, 4).ToLower() + item.Name.Substring(6, 1).ToUpper() + item.Name.Substring(7).ToLower();/*实体名大写*/
                    string entityName = "LasaAnnotation";
                    uow.Db.MappingTables.Add(entityName, item.Name);
                    //foreach (var col in db.DbMaintenance.GetColumnInfosByTableName(item.Name))
                    //{
                    //    db.MappingColumns.Add(col.DbColumnName.ToUpper() /*类的属性大写*/, col.DbColumnName, entityName);
                    //}
                }
                uow.Db.DbFirst.Where(r => r.ToLower().StartsWith("lasa_annotation")).IsCreateAttribute().CreateClassFile("E:\\低空态势感知\\code\\OpenAuth.Repository\\Domain", "OpenAuth.Repository.Domain");
                uow.Commit();
            }
            return "更新实体成功";
        }
        #endregion



        #endregion


        /// <summary>
        /// 上传用户信息
        /// </summary>
        /// <param name="formFiles"></param>
        /// <returns></returns>
        public Response<bool> ImportUserInfo(IFormFileCollection formFiles)
        {
            IFormFile file = formFiles[0];
            //存储文件到服务器
            if (file != null)
            {
                if (file.FileName.IndexOf(".xls") > 0 || file.FileName.IndexOf(".xlsx") > 0)
                {
                    //数据库导入
                    IWorkbook workbook = null;
                    if (file.FileName.IndexOf(".xlsx") > 0)
                    {
                        using (var stream = file.OpenReadStream())
                        {
                            workbook = new XSSFWorkbook(stream);//excel的版本2007
                        }
                    }
                    else if (file.FileName.IndexOf(".xls") > 0)
                    {
                        using (var stream = file.OpenReadStream())
                        {
                            workbook = new HSSFWorkbook(stream);//excel的版本2003
                        }
                    }

                    //数据处理
                    using (var uow = base.UnitWork.CreateContext())
                    {
                        //获取sheet
                        ISheet sheet;
                        sheet = workbook.GetSheetAt(0);
                        //处理sheet数据
                        string res = "";
                        if (sheet != null)
                        {
                            IRow firstRow = sheet.GetRow(0);
                            //获取有效数据行数
                            int lastRow = sheet.LastRowNum;
                            int rowCount = 0;
                            //具体excel数据解析
                            for (int i = 1; i <= lastRow; ++i)
                            {
                                IRow row = sheet.GetRow(i);
                                if (row == null || string.IsNullOrEmpty(row.GetCell(0).ToString())) continue;

                                SysUser user = new SysUser();
                                user.Id = YitIdHelper.NextId();
                                user.CreateTime = DateTime.Now;
                                user.Name = row.GetCell(4).ToString();
                                user.CreateId = _auth.GetCurrentUser().User.Id;
                                user.Account=row.GetCell(5).ToString();
                                user.Password = Md5Helper.Encrypt(user.Account, 32).ToLower();

                                if (uow.User.IsAny(u => u.Account == user.Account))
                                {
                                    res += "账号" + user.Account + "已存在,";
                                }
                                else
                                {
                                    user.Secretkey = Md5Helper.Encrypt(CommonHelper.CreateNo(), 16).ToLower();
                                    if (string.IsNullOrEmpty(user.Password))
                                    {
                                        user.Password = Md5Helper.Encrypt(DESEncrypt.Encrypt(Md5Helper.Hash(user.Account), user.Secretkey).ToLower(), 32).ToLower();   //如果客户端没提供密码，默认密码同账号
                                    }
                                    else
                                    {
                                        
                                        user.Password = Md5Helper.Encrypt(DESEncrypt.Encrypt(user.Password, user.Secretkey).ToLower(), 32).ToLower();
                                    }
                                     uow.User.Insert(user);

                                    if (!string.IsNullOrEmpty(row.GetCell(7).ToString()))
                                    {
                                        //为用户分配角色
                                        SysUserRole userrole = new SysUserRole();
                                        userrole.UserId = user.Id;
                                        userrole.RoleId = Convert.ToInt64(row.GetCell(7).ToString());
                                        //删除用户相关角色
                                         uow.SysUserRole.DeleteById(user.Id);
                                        //添加
                                        uow.SysUserRole.Insert(userrole);
                                    }

                                    if (!string.IsNullOrEmpty(row.GetCell(2).ToString()))
                                    {
                                        //为用户分配部门
                                        SysUserOrg userorg = new SysUserOrg();
                                        userorg.UserId = user.Id;
                                        userorg.OrgId = Convert.ToInt64(row.GetCell(2).ToString());
                                        userorg.PositionId = 0;
                                        userorg.Level = Convert.ToInt16(row.GetCell(3).ToString());
                                        //删除用户相关部门
                                        uow.SysUserOrg.DeleteById(user.Id);
                                        //重新添加本次部门
                                        uow.SysUserOrg.Insert(userorg);
                                    }
                                }                                
                            }
                        }
                        var flag = uow.Commit();

                        return new Response<bool>
                        {
                            Result = flag,
                            Message = flag == true ? "更新成功  "+res : "更新失败"
                        };
                    }
                }
                else
                {
                    return new Response<bool>
                    {
                        Result = false,
                        Message = "上传文件类型错误，请上传Excel文件"
                    };
                }
            }
            else
            {
                return new Response<bool>
                {
                    Result = false,
                    Message = "文件为空"
                };
            }
        }
    }
} 