using CloudBuilder.Core.DatabaseAccessor;
using CloudBuilder.Core.DatabaseAccessor.Entity;
using CloudBuilder.Core.Extensions;
using CloudBuilder.Core.Policy;
using CloudBuilder.Core.Service;
using CloudBuilder.Security.Data;
using CloudBuilder.Security.Entity;
using CloudBuilder.Security.Policy;
using CloudBuilder.Security.SearchCriteria;
using CloudBuilder.Security.Service.Authorization;
using CloudBuilder.Security.Utility;
using DocumentFormat.OpenXml.Spreadsheet;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Security.Permissions;
namespace CloudBuilder.Security.Service
{
    public class SecurityUserService : ISecurityUserService
    {
        private readonly IApplicationService service;
        private readonly IHttpContextAccessor httpContextAccessor;
        private IRepository<SecurityUserEntity> repository;
        public SecurityUserService(IApplicationService service, IHttpContextAccessor httpContextAccessor)
        {
            this.service = service;
            this.httpContextAccessor = httpContextAccessor;
            repository = service.GetRepository<IRepository<SecurityUserEntity>>();
        }

        [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Find)]
        public SecurityUserEntity FindByStaffId(string staffid)
        {
            return repository.DetachedEntities.Where(x => x.UserName == staffid).FirstOrDefault();
        }

        [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Find)]
        public SecurityUserData FindByKey(string key)
        {
            SecurityUserData data = new SecurityUserData();
            if (string.IsNullOrEmpty(key)) return data;

            SecurityUserEntity user = repository.DetachedEntities.Where(x => x.UserName == key).FirstOrDefault();

            if (user == null) return data;

            string uid = service.UserId;

            PermissionContext permissionContext = new PermissionContext(service);

            if (user.UserName != uid && permissionContext.CanView(SecurityPermissionPolicy.CanSeeAllUser))
            {
                return data;
            }

            data.SecurityUser = new SecurityUserDisplayData(user);

            IRepository<SecurityUserActorViewEntity> repositoryUav = repository.GetRepository<IRepository<SecurityUserActorViewEntity>>();

            data.SecurityUserActors = repositoryUav.DetachedEntities.Where(x => x.UserName == key).ToArray();

            return data;
        }

        [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Find)]
        public SecurityUserEntity[] FindAll()
        {
            return repository.DetachedEntities.ToArray();
        }

        [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Find)]
        public SecurityUserResultData FindBySearchCriteria(SecurityUserSearchCriteria criteria)
        {
            SecurityUserResultData data = new SecurityUserResultData();
            SecurityUserEntity[] list = null;

            int count = 0;

            string sqlWhere = null;

            if (criteria.Filter != null && criteria.Filter.Length > 0)
            {
                sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter);
            }

            //sqlWhere = sqlWhere + string.Format(" and {0} ='{1}' ", SecurityUserEntity.DB_USER_IS_VALID_INDC, YesNoPolicy.YES);

            SecurityUserEntity entity = SecurityUserEntity.GetInstance();
            string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page, criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere);



            string err = null;
            try
            {
                list = repository.FromSql(sql).ToArray();
            }
            catch (System.Exception ex)
            {
                err = ex.Message;
            }


            if (list != null && list.Length > 0)
            {
                sql = entity.GetSelectCountFrom(sqlWhere);
                count = (int)repository.ExecuteScalar(sql);
            }

            data.Limit = criteria.limit;
            data.Page = criteria.page;
            data.Datas = list;
            data.Total = count;
            //data.Sql = sql;
            data.ErrorMessage = err;
            return data;
        }

        [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Print)]
        public dynamic PrintBySearchCriteria(SecurityUserSearchCriteria criteria)
        {
            throw new NotImplementedException();
        }

        [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Insert)]
        [UnitOfWork]
        public SecurityUserData Insert(SecurityUserData data)
        {
            SecurityUserEntity securityUser = repository.DetachedEntities.Where(x => x.UserName == data.SecurityUser.UserName).FirstOrDefault();
            if (securityUser != null)
            {
                throw new ValidatedException("记录已存在.");
            }

            ValidateHelper.Validate(service, data.SecurityUser, SecurityUserEntity.DB_NAME_SECURITY_USER);

            securityUser = new SecurityUserEntity();

            ObjectCopyHelper.Copy(data.SecurityUser, securityUser);
            if (!string.IsNullOrEmpty(data.SecurityUser.OrgUserPassword))
                securityUser.UserPassword = data.SecurityUser.OrgUserPassword.GetMd5();

            securityUser.UserIsValidIndc = YesNoPolicy.YES;
            repository.InsertNow(securityUser);

            SaveSecurityUserActor(data);

            return FindByKey(data.SecurityUser.UserName);
        }

        [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Update)]
        [UnitOfWork]
        public SecurityUserData Update(SecurityUserData data)
        {
            SecurityUserEntity SecurityUser = repository.DetachedEntities.Where(x => x.UserName == data.SecurityUser.UserName).FirstOrDefault();
            if (SecurityUser == null)
            {
                throw new ValidatedException("记录不存在.");
            }

            ValidateHelper.Validate(service, data.SecurityUser, SecurityUserEntity.DB_NAME_SECURITY_USER);

            ObjectCopyHelper.Copy(data.SecurityUser, SecurityUser);

            if (!string.IsNullOrEmpty(data.SecurityUser.OrgUserPassword))
            {
                SecurityUser.UserPassword = data.SecurityUser.OrgUserPassword.GetMd5();
            }

            repository.UpdateNow(SecurityUser);

            SaveSecurityUserActor(data);

            return FindByKey(data.SecurityUser.UserName);
        }

        private void SaveSecurityUserActor(SecurityUserData data)
        {
            IRepository<SecurityUserActorEntity> repositoryUa = repository.GetRepository<IRepository<SecurityUserActorEntity>>();

            SecurityUserActorEntity[] olds = repositoryUa.Entities.Where(x => x.UserName == data.SecurityUser.UserName).ToArray();
            if (olds != null && olds.Length > 0)
            {
                foreach (SecurityUserActorEntity old in olds)
                {
                    repositoryUa.DeleteNow(old);
                }
            }

            if (data.SecurityUserActors != null && data.SecurityUserActors.Length > 0)
                foreach (SecurityUserActorViewEntity dto in data.SecurityUserActors)
                {
                    repositoryUa.InsertNow(new SecurityUserActorEntity()
                    {
                        UserName = data.SecurityUser.UserName,
                        ActorName = dto.ActorName,
                    });
                }

        }


        [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Delete)]
        [UnitOfWork]
        public void Delete(string key)
        {
            SecurityUserEntity securityUser = repository.DetachedEntities.Where(x => x.UserName == key).FirstOrDefault();
            if (securityUser == null)
            {
                throw new ValidatedException("记录不存在.");
            }

            securityUser.UserIsValidIndc = "N";
            repository.UpdateNow(securityUser);

        }

        [PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Delete)]
        [UnitOfWork]
        public void Deletes(string[] keys)
        {
            foreach (string key in keys)
            {
                Delete(key);
            }
        }

        [AllowAnonymous]
        public SecurityFunctionResultData FindMenuByUsername()
        {
            string username = service.UserId;

            if (string.IsNullOrEmpty(username)) return null;

            SecurityFunctionResultData data = new SecurityFunctionResultData();

            var userActors = service.GetRepository<IRepository<SecurityUserActorEntity>>().DetachedEntities.Where(x => x.UserName == username);

            var actorGroups = service.GetRepository<IRepository<SecurityActorGroupEntity>>().DetachedEntities.Where(x => userActors.Select(x => x.ActorName).Contains(x.ActorName));

            var groupPermissions = service.GetRepository<IRepository<SecurityGroupPermissionEntity>>().DetachedEntities.Where(x => actorGroups.Select(x => x.GroupName).Contains(x.GroupName));

            var pfMaps = service.GetRepository<IRepository<SecurityPermissionFunctionMapEntity>>().DetachedEntities.Where(x => groupPermissions.Select(x => x.PermissionName).Contains(x.PermissionName));

            SecurityFunctionEntity[] securityFunctions = service.GetRepository<IRepository<SecurityFunctionEntity>>().DetachedEntities.Where(x => pfMaps.Select(x => x.FunctionName).Contains(x.FunctionName)).ToArray();
            if (securityFunctions == null || securityFunctions.Length == 0) return null;

            SecurityFunctionMapEntity[] securityFunctionMaps = service.GetRepository<IRepository<SecurityFunctionMapEntity>>().DetachedEntities.ToArray();

            SecurityFunctionEntity[] functions = service.GetRepository<IRepository<SecurityFunctionEntity>>().DetachedEntities.ToArray();

            if (securityFunctionMaps == null || securityFunctionMaps.Length == 0) return null;

            List<SecurityFunctionDisplayData> displayDatas = new List<SecurityFunctionDisplayData>();
            List<SecurityFunctionMapEntity> maps = new List<SecurityFunctionMapEntity>();

            foreach (var securityFunction in securityFunctions)
            {
                PackSecurityFunction(displayDatas, maps, securityFunction, functions, securityFunctionMaps);
            }

            data.SecurityFunctionMaps = maps.ToArray();
            data.SecurityFunctionDisplayDatas = displayDatas.OrderBy(x => x.Orderby).ToArray();

            return data;
        }

        private int GetOrderBy(string functionName, ref int level, SecurityFunctionEntity[] securityFunctions, SecurityFunctionMapEntity[] securityFunctionMaps, int baseOrderBy)
        {
            SecurityFunctionMapEntity[] parents = securityFunctionMaps.Where(x => x.FunctionNameSon == functionName).ToArray();
            int orderBy = 0;
            if (parents != null && parents.Length > 0)
            {
                if (level > 0)
                    return parents.FirstOrDefault().Orderby * 10000 + baseOrderBy;
                else
                    orderBy = baseOrderBy * 100;
            }
            else
            {
                return baseOrderBy * 1000000;
            }

            foreach (var parent in parents)
            {
                level = 0;
                SecurityFunctionEntity f = securityFunctions.Where(x => x.FunctionName == parent.FunctionNameParent).FirstOrDefault()!;
                if (f == null || f.FunctionName == SecurityFunctionResultData.BOOTUP) continue;
                level += 1;
                SecurityFunctionMapEntity[] ps = securityFunctionMaps.Where(x => x.FunctionNameSon == functionName).ToArray();

                orderBy = GetOrderBy(f.FunctionName, ref level, securityFunctions, securityFunctionMaps, parents.FirstOrDefault().Orderby * 100 + baseOrderBy);
            }

            if (level == 0) orderBy = parents.FirstOrDefault().Orderby * 10000 + orderBy;

            return orderBy;
        }

        private void PackSecurityFunction(List<SecurityFunctionDisplayData> displayDatas, List<SecurityFunctionMapEntity> maps, SecurityFunctionEntity securityFunction, SecurityFunctionEntity[] securityFunctions, SecurityFunctionMapEntity[] securityFunctionMaps)
        {
            if (!displayDatas.Select(x => x.FunctionName).Contains(securityFunction.FunctionName))
            {
                SecurityFunctionMapEntity[] parents = securityFunctionMaps.Where(x => x.FunctionNameSon == securityFunction.FunctionName).ToArray();

                int orderby = 0;
                if (parents != null && parents.Length > 0)
                {
                    foreach (var parent in parents)
                    {
                        int level = 0;
                        orderby = GetOrderBy(parent.FunctionNameParent, ref level, securityFunctions, securityFunctionMaps, parent.Orderby);

                        displayDatas.Add(new SecurityFunctionDisplayData(securityFunction) { Orderby = orderby, FunctionNameParent = parent.FunctionNameParent });
                    }
                }
                else
                {
                    //顶级菜单
                    orderby = 1000000;
                    displayDatas.Add(new SecurityFunctionDisplayData(securityFunction) { Orderby = orderby });
                }



                foreach (var parent in parents)
                {
                    SecurityFunctionEntity f = securityFunctions.Where(x => x.FunctionName == parent.FunctionNameParent).FirstOrDefault()!;
                    if (f == null) continue;
                    maps.Add(parent);
                    PackSecurityFunction(displayDatas, maps, f, securityFunctions, securityFunctionMaps);
                }
            }
        }


        [AllowAnonymous]
        public void UpdateLocalName(string localName)
        {
            SecurityUserEntity securityUser = repository.DetachedEntities.Where(x => x.UserName == service.UserId && x.UserIsValidIndc == YesNoPolicy.YES).FirstOrDefault();
            if (securityUser == null)
            {
                throw new ValidatedException("用户不存在.");
            }
            securityUser.UserLocalName = localName;
            repository.UpdateNow(securityUser);

        }
    }
}
