using Infrastructure;
using Infrastructure.Extensions;
using OpenAuth.App.Base;
using OpenAuth.App.Base.Tree;
using OpenAuth.App.BasicQueryService;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.Repository;
using OpenAuth.Repository.Core;
using OpenAuth.Repository.Domain;
using SqlSugar;
using SqlSugar.Extensions;
using System.Collections.Generic;
using System.Diagnostics;

namespace OpenAuth.App
{
    public class OrgManagerApp : LongTreeApp<SysOrg, SugarDbContext>
    {
        UserManager userManager;

        private ISqlSugarClient client;
        public OrgManagerApp(
            ISugarUnitOfWork<SugarDbContext> unitWork,
            ISimpleClient<SysOrg> repository,
             ISqlSugarClient sqlSugarClient,
            UserManager userManager,
            IAuth auth) : base(unitWork, repository, auth)
        {
            this.client = sqlSugarClient;
            this.userManager = userManager;

        }

        #region 查询

        #region 部门树
        /// <summary>
        /// name 为空查全部
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public async Task<Response<List<TreeItemLong>>> OrgsAllTree(string name)
        {
            var result = new Response<List<TreeItemLong>>();
            var user = _auth.GetCurrentUser().User;
            string sql = "select \"min\"(\"Level\") from sys_userorg  where \"UserId\"='" + user.Id + "' ";
            var level = client.Ado.GetInt(sql);
            if (level>0)
            {
              
                string sql2 = "select \"OrgId\" from sys_userorg where \"Level\"="+level + " and \"UserId\"='" + user.Id + "' ";
                List<long> orgIds1 =  client.Ado.SqlQuery<long>(sql2);
                int count = orgIds1.Count;
                for (int i = 0; i < count; i++) {
                    List<long> longs  =  getAllChildOrgId(orgIds1[i]);
                    orgIds1.AddRange(longs);
                }

                var orglist = base.Repository.AsSugarClient().Queryable<SysUserOrg>()
                            .Where(a => a.UserId == user.Id).Select(a => a.OrgId)
                            .ToList();
                var query = base.Repository.AsQueryable().Where(a => orgIds1.Contains(a.Id) || a.CreateId == user.Id)
                    .Select<TreeItemLong>();

                if (!string.IsNullOrEmpty(name))
                {
                    object[] orgIds = (await base.Repository.AsQueryable()
                        .Where(a => a.Name.Contains(name))
                        .Select(it => it.Id).ToListAsync()).Cast<object>().ToArray();

                    result.Result = await query.ToTreeAsync(a => a.Children, a => a.ParentId, 0, orgIds);
                }
                else
                {
                    result.Result = await query.ToTreeAsync(a => a.Children, a => a.ParentId, 0, a => a.Id);
                }

                return result;
            }
            else {
                var query = base.Repository.AsQueryable()
                   .Select<TreeItemLong>();

                if (!string.IsNullOrEmpty(name))
                {
                    object[] orgIds = (await base.Repository.AsQueryable()
                        .Where(a => a.Name.Contains(name))
                        .Select(it => it.Id).ToListAsync()).Cast<object>().ToArray();

                    result.Result = await query.ToTreeAsync(a => a.Children, a => a.ParentId, 0, orgIds);
                }
                else
                {
                    result.Result = await query.ToTreeAsync(a => a.Children, a => a.ParentId, 0, a => a.Id);
                }

                return result;
            }
        }
        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;
        }
        /// <summary>
        /// name 为空查全部
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public async Task<Response<List<TreeItemLong>>> OrgsTree(string name)
        {
            /*  var result = new Response<List<TreeItemLong>>();

              var userId = long.Parse(_auth.GetUserId());

              var query = userManager.UserOrgs(userId);

              var orgs = await query
                  .WhereIF(!string.IsNullOrEmpty(name), (u, o) => o.Name.Contains(name))
                  .Select<TreeItemLong>().ToListAsync();

              //if (!string.IsNullOrEmpty(name))
              //{
              //    object[] orgIds = (await query
              //        .Where((u, o) => o.Name.Contains(name))
              //        .Select((u, o) => o.Id).ToListAsync()).Cast<object>().ToArray();

              //    result.Result = await query.Select<TreeItemLong>()
              //                    .ToTreeAsync(a => a.Children, a => a.ParentId, 0, orgIds);
              //}
              //else
              //{
              //    result.Result = await query.Select<TreeItemLong>()
              //                        .ToTreeAsync(a => a.Children, a => a.ParentId, 0, a => a.Id);
              //}

              result.Result = orgs.BuildTree().ToList();

              return result;*/
            var result = new Response<List<TreeItemLong>>();
            var user = _auth.GetCurrentUser().User;
            string sql = "select \"min\"(\"Level\") from sys_userorg  where \"UserId\"='" + user.Id + "' ";
            var level = client.Ado.GetInt(sql);
            if ( level > 0)
            {

                string sql2 = "select \"OrgId\" from sys_userorg where \"Level\"=" + level + " and \"UserId\"='" + user.Id + "' ";
                List<long> orgIds1 = client.Ado.SqlQuery<long>(sql2);
                 int count = orgIds1.Count;
                for (int i = 0; i < count; i++)
                {
                    List<long> longs = getAllChildOrgId(orgIds1[i]);
                    orgIds1.AddRange(longs);
                }

               
                var query = await base.Repository.AsQueryable().Where(a => orgIds1.Contains(a.Id) || a.CreateId == user.Id)
                    .Select<TreeItemLong>().ToListAsync();

                if (!string.IsNullOrEmpty(name))
                {
                    object[] orgIds = (await base.Repository.AsQueryable()
                        .Where(a => a.Name.Contains(name))
                        .Select(it => it.Id).ToListAsync()).Cast<object>().ToArray();

                    result.Result = query.BuildTree().ToList();
                }
                else
                {
                    result.Result = query.BuildTree().ToList();
                }

                return result;
            }
            else
            {
                var query = base.Repository.AsQueryable()
                   .Select<TreeItemLong>();

                if (!string.IsNullOrEmpty(name))
                {
                    object[] orgIds = (await base.Repository.AsQueryable()
                        .Where(a => a.Name.Contains(name))
                        .Select(it => it.Id).ToListAsync()).Cast<object>().ToArray();

                    result.Result = await query.ToTreeAsync(a => a.Children, a => a.ParentId, 0, orgIds);
                }
                else
                {
                    result.Result = await query.ToTreeAsync(a => a.Children, a => a.ParentId, 0, a => a.Id);
                }

                return result;
            }
        }

        /// <summary>
        /// 部门和职级组合树
        /// </summary>
        /// <returns></returns>
        public async Task<Response<List<TreeItemLong>>> OrgPositonTree()
        {
            var client = base.Repository.AsSugarClient();

            var orgQuery = base.Repository.AsQueryable()
                                     .Select(a => new TreeItemLong { Key = 0, Tag = "" }, true);

            var posQuery = client.Queryable<SysPosition, SysOrg>((p, o) =>
                        new JoinQueryInfos(JoinType.Left, p.GroupId == o.PosGroupId))
                        .Where((p, o) => o.Id != null)
                        .Select((p, o) => new TreeItemLong
                        {
                            Key = p.Id,
                            Tag = o.Id.ToString(),
                            Id = p.Id,
                            Name = p.Name,
                            ParentId = p.ParentId == 0 ? o.Id : p.ParentId,
                        });

            var poses = posQuery.ToList();

            var list = await client.UnionAll(orgQuery, posQuery)
                                   .Mapper(a =>
                                   {
                                       if (a.Id == a.Key)
                                       {
                                           var item = poses.Where(m => m.Id == a.Id).First();
                                           item.Id = Yitter.IdGenerator.YitIdHelper.NextId();

                                           a.Id = item.Id;

                                           var parent = poses.Where(m => m.Key == a.ParentId && m.Tag == a.Tag).FirstOrDefault();
                                           if (parent != null)
                                           {
                                               a.ParentId = parent.Id;
                                           }
                                       }
                                   })
                                   .ToTreeAsync(a => a.Children, a => a.ParentId, 0, a => a.Id);

            return new Response<List<TreeItemLong>>
            {
                Result = list
            };

        }
        #endregion

        #region 分页
        /// <summary>
        /// 查询部门列表
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        public async Task<Response<PageInfo<List<SysOrg>>>> LoadAllPage(QueryOrgListReq req)
        {
            var user = _auth.GetCurrentUser().User;
            string sql = "select \"min\"(\"Level\") from sys_userorg  where \"UserId\"='" + user.Id + "' ";
            var level = client.Ado.GetInt(sql);
            if ( level > 0)
            {

                string sql2 = "select \"OrgId\" from sys_userorg where \"Level\"=" + level + " and \"UserId\"='" + user.Id + "' ";
                List<long> orgIds1 = client.Ado.SqlQuery<long>(sql2);
                int count = orgIds1.Count;
                for (int i = 0; i < count; i++)
                {
                    List<long> longs = getAllChildOrgId(orgIds1[i]);
                    orgIds1.AddRange(longs);
                }
                RefAsync<int> totalCount = 0;

                var orgs = await base.Repository.AsQueryable()
                    .WhereIF(req.OrgId != 0, o => o.ParentId == req.OrgId)
                    .WhereIF(!string.IsNullOrEmpty(req.key), o => o.Name.Contains(req.key))
                    .Where(a => orgIds1.Contains(a.Id) || a.CreateId == user.Id)
                    .OrderByDescending(o => o.CreateTime)
                    .ToPageListAsync(req.page, req.limit, totalCount);

                return new Response<PageInfo<List<SysOrg>>>
                {
                    Result = new PageInfo<List<SysOrg>>
                    {
                        Items = orgs,
                        Total = totalCount
                    }
                };
            }
            else {
                RefAsync<int> totalCount = 0;

                var orgs = await base.Repository.AsQueryable()
                    .WhereIF(req.OrgId != 0, o => o.ParentId == req.OrgId)
                    .WhereIF(!string.IsNullOrEmpty(req.key), o => o.Name.Contains(req.key))
                    .OrderByDescending(o => o.CreateTime)
                    .ToPageListAsync(req.page, req.limit, totalCount);

                return new Response<PageInfo<List<SysOrg>>>
                {
                    Result = new PageInfo<List<SysOrg>>
                    {
                        Items = orgs,
                        Total = totalCount
                    }
                };
            }
                
        }

        public async Task<Response<PageInfo<List<SysOrg>>>> LoadPage(QueryOrgListReq req)
        {

            var user = _auth.GetCurrentUser().User;
            string sql = "select \"min\"(\"Level\") from sys_userorg  where \"UserId\"='" + user.Id + "' ";
            var level = client.Ado.GetInt(sql);
            if (level > 0)
            {

                string sql2 = "select \"OrgId\" from sys_userorg where \"Level\"=" + level + " and \"UserId\"='" + user.Id + "' ";
                List<long> orgIds1 = client.Ado.SqlQuery<long>(sql2);
                int count = orgIds1.Count;
                for (int i = 0; i < count; i++)
                {
                    List<long> longs = getAllChildOrgId(orgIds1[i]);
                    orgIds1.AddRange(longs);
                }
                RefAsync<int> totalCount = 0;

                var orgs = await base.Repository.AsQueryable()
                    .WhereIF(req.OrgId != 0, o => o.ParentId == req.OrgId)
                    .WhereIF(!string.IsNullOrEmpty(req.key), o => o.Name.Contains(req.key))
                    .Where(a => orgIds1.Contains(a.Id) || a.CreateId == user.Id)
                    .OrderByDescending(o => o.CreateTime)
                    .ToPageListAsync(req.page, req.limit, totalCount);

                return new Response<PageInfo<List<SysOrg>>>
                {
                    Result = new PageInfo<List<SysOrg>>
                    {
                        Items = orgs,
                        Total = totalCount
                    }
                };
            }
            else
            {
                RefAsync<int> totalCount = 0;

                var userId = long.Parse(_auth.GetUserId());

                var orgs = await userManager.UserOrgs(userId)
                    .WhereIF(req.OrgId != 0, (u, o) => o.ParentId == req.OrgId)
                    .WhereIF(!string.IsNullOrEmpty(req.key), (u, o) => o.Name.Contains(req.key))
                    .OrderByDescending((u, o) => o.CreateTime)
                    .Select((u, o) => o)
                    .ToPageListAsync(req.page, req.limit, totalCount);

                return new Response<PageInfo<List<SysOrg>>>
                {
                    Result = new PageInfo<List<SysOrg>>
                    {
                        Items = orgs,
                        Total = totalCount
                    }
                };
            }
           
        }
        #endregion

        #region 实体
        public SysOrg Get(string id)
        {
            return Repository.GetById(id);
        }
        #endregion

        #region 子节点
        public async Task<List<SysOrg>> LoadChildren(long? parentId)
        {
            SysUser user = _auth.GetCurrentUser().User;
            //string sql = "select \"min\"(\"Level\") from sys_userorg  where \"UserId\"='"+user.Id+"' ";
            //var level = client.Ado.GetInt(sql);
            /*if (user.Id == -1||level==0)
            {*/
            List<SysOrg> children = new List<SysOrg>();
            if (parentId != null)
            {
                children= await base.Repository.AsQueryable().Where(r=>r.ParentId==parentId).OrderBy(r=>r.SortNo).ToListAsync();
            }
            return children;
          /*  }
            else
            {
                if (parentId == 0)
                {
                    return await base.Repository.GetListAsync(a => a.ParentId == parentId);
                } else if(parentId== 371300)
                {
                    var orglist = base.Repository.AsSugarClient().Queryable<SysUserOrg>()
                            .Where(a => a.UserId == user.Id).Select(a => a.OrgId)
                            .ToList();
                    return await base.Repository.GetListAsync(a => orglist.Contains(a.Id) || a.CreateId == user.Id);
                }
                else
                {
                    var orglist = base.Repository.AsSugarClient().Queryable<SysUserOrg>()
                       .Where(a => a.UserId == user.Id).Select(a => a.OrgId)
                       .ToList();
                    return await base.Repository.GetListAsync(a => a.ParentId == parentId && orglist.Contains(a.Id) || a.CreateId == user.Id);
                }

            }*/
        }

        #region 用户关联的部分和职级
        public async Task<List<SysUserOrg>> UserOrgs(long userId)
        {
            return await base.Repository.AsSugarClient().Queryable<SysUserOrg>()
                    .Where(a => a.UserId == userId)
                    .ToListAsync();
        }
        #endregion
        #endregion

        #region  父节点
        public async Task<List<SysOrg>> LoadParents(long childId)
        {
            return await client.Queryable<SysOrg>().ToParentListAsync(it => it.ParentId, childId);
        }
        #endregion

        #endregion

        #region 增删改

        #region 增加
        /// <summary>
        /// 添加部门
        /// </summary>
        /// <param name="sysOrg">The org.</param>
        /// <returns>System.Int32.</returns>
        /// <exception cref="System.Exception">未能找到该组织的父节点信息</exception>
        public Response<bool> Add(OrgForm org)
        {
            var loginContext = _auth.GetCurrentUser();
            if (loginContext == null)
            {
                throw new CommonException("登录已过期", Define.INVALID_TOKEN);
            }

            SysOrg model = org.MapTo<SysOrg>();

            //后边再看
            //CalculateCascade(model);

            using (var uow = base.UnitWork.CreateContext())
            {
                if (model.Id <= 0) {
                    model.Id = Yitter.IdGenerator.YitIdHelper.NextId();
                }

                model.ParentName = getParentName(model.ParentId);
                model.CreateId = loginContext.User.Id;
                model.CreateTime = DateTime.Now;
                if (model.ParentId == 0) {
                    model.Level = 0;
                    model.CascadeId = "0."+model.Id;
                }else
                {
                    long parentId = model.ParentId;
                    int Level = 0;
                    string cascade = "";
                    while (true)
                    {
                        String sql = "select \"ParentId\" from sys_org where \"Id\"=" + parentId;
                        long id = client.Ado.GetLong(sql);
                       // long id = base.Repository.AsSugarClient().Queryable<SysOrg>().Where(a => a.Id == parentId).Select(a => a.ParentId).ToLong();
                        if (!string.IsNullOrEmpty(cascade)) {
                            cascade = id + "." + cascade;
                        }else
                        {
                            cascade = id + cascade;
                        }
                       
                        parentId = id;
                        Level++;
                        if (id == 0) { 
                        break; }}
                    model.Level = Level;
                    model.CascadeId = cascade+"."+model.ParentId+"."+model.Id;
                }
               
                uow.SysOrg.Insert(model);
                var falg = uow.Commit();
                return new Response<bool>
                {
                    Result = falg,
                    Message = (falg == true ? "添加成功" : "添加失败")
                };
            }
        }
        #endregion

        #region 修改
        public Response<bool> Update(SysOrg sysOrg)
        {
            if (sysOrg.Id == sysOrg.ParentId)
            {
                throw new Exception("上级节点不能为自己");
            }
            try
            {
                var user = _auth.GetCurrentUser().User;
                sysOrg.ParentName=getParentName(sysOrg.ParentId);
                sysOrg.CreateId = user.Id;
                UpdateSysOrg(sysOrg);

                return new Response<bool> { Result = true, Message = "success" };
            }
            catch (Exception ex)
            {
                return new Response<bool> { Result = false, Message = "error:" + ex.Message.ToString() };
            }
        }
        #endregion

        #region 删除
        /// <summary>
        /// 删除指定ID的部门及其所有子部门
        /// </summary>
        public Response<bool> DelOrgCascade(string[] ids)
        {
            var delOrgCascadeIds = base.Repository.GetList(u => ids.Contains(u.Id.ToString())).Select(u => u.CascadeId).ToArray();
            var delOrgIds = new List<long>();
            foreach (var cascadeId in delOrgCascadeIds)
            {
                delOrgIds.AddRange(base.Repository.GetList(u => u.CascadeId.Contains(cascadeId)).Select(u => u.Id).ToArray());
            }

            using (var uow = base.UnitWork.CreateContext())
            {
                //得改 代码先注释
                //uow.Relevance.Delete(u => u.Key == Define.USERORG && delOrgIds.Contains(u.SecondId));
                uow.SysOrg.Delete(u => delOrgIds.Contains(u.Id));
                var flag = uow.Commit();

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

        #region 分配职级组
        /// <summary>
        /// 为部门分配职级组
        /// </summary>
        /// <param name="assignOrgPos"></param>
        /// <returns></returns>
        public async Task<Response<bool>> OrgPosGroup(AssignOrgPosGroup assignOrgPos)
        {
            var flag = await base.Repository.UpdateAsync(a => new SysOrg { PosGroupId = assignOrgPos.PosGroupId }, a => a.Id == assignOrgPos.OrgId);
            return new Response<bool>
            {
                Result = flag,
                Message = flag == true ? "success" : "error"
            };
        }
        #endregion

        #endregion
        public string getParentName(long parentId) {
            string name = base.Repository.AsSugarClient().Queryable<SysOrg>().First(a => a.Id == parentId).Name;
            return name;
        }




        public void UpdateSysOrg(SysOrg obj)
        {
            if (obj.ParentId == 0)
            {
                obj.Level = 0;
                obj.CascadeId = "0." + obj.Id;
            }
            else
            {
                long parentId = obj.ParentId;
                int Level = 0;
                string cascade = "";
                while (true)
                {
                    string sql = "select \"ParentId\" from sys_org where \"Id\"=" + parentId;
                    long id = base.Repository.AsSugarClient().Ado.GetLong(sql);
                    //long id = base.Repository.AsSugarClient().Queryable<SysOrg>().Where(a => a.Id == parentId).Select(a => a.ParentId).ToLong();
                    if (!string.IsNullOrEmpty(cascade))
                    {
                        cascade = id + "." + cascade;
                    }
                    else
                    {
                        cascade = id + cascade;
                    }

                    parentId = id;
                    Level++;
                    if (id == 0)
                    {
                        break;
                    }
                }
                obj.Level = Level;
                obj.CascadeId = cascade + "." + obj.ParentId + "." + obj.Id;
            }
            base.Repository.AsSugarClient().Updateable<SysOrg>(obj).ExecuteCommand();
        }



    }
}