using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Data.Entity;

using BLL.Base;
using BLL.Services.System;
using Model.Entities.Users;
using Model.UnitsOfWork;
using Model.ViewModel;
using Model.ViewModel.Edit;

namespace BLL.Services.Mapper
{
    public class UserMapper : BaseServices
    {
        readonly PermissionServices permissionServices;

        public UserMapper(UOW UOW, PermissionServices permissionServices) : base(UOW) { this.permissionServices = permissionServices; }


        public List<GroupInfo> GroupToGroupInfo_ForUsers()
        {
            return UOW.Repo_Group.All_NoTrack_List.
                        Where(e => e.Name != EnumDefaultGroups.Анонимные.ToString()).
                        Select(e => new GroupInfo()
                        {
                            ID = e.ID,
                            Name = e.Name                            
                        }).ToList();
        }
        public List<RootDirInfo> RootDirs()
        {
            var dirs = UOW.Repo_SRootDirectory.All_List;

            return new List<RootDirInfo>(dirs.Select(e => new RootDirInfo()
            {
                ID = e.ID,
                Name = e.Name,
                CanDownload = false,
                CanOpen = false,
                CanUpload = false
            }));
        }


        public List<EditUserModel> UserToEditUser_List()
        {
            var users = UOW.Repo_User.All_NoTrack.
                Include(e => e.Groups).ToList();
            var groups = UOW.Repo_Group.All_NoTrack_List.
                Where(e => e.Name != EnumDefaultGroups.Анонимные.ToString());

            return users.Select(e => new EditUserModel()
            {
                ID = e.ID,
                Name = e.Login,
                Password = "",
                Changes = EnumChanges.NoChange,
                Active = e.IsActive,
                Groups = groups.Select(e2 => new GroupInfo()
                {
                    ID = e2.ID,
                    Name = e2.Name,
                    EnterInGroup = e.Groups.FirstOrDefault(e3 => e3.ID == e2.ID) != null
                }).ToList()
            }).ToList();
        }

        public List<(EditUserModel Edited, User DBUser)> EditUserToUser_List(List<EditUserModel> editUsers)
        {
            List<(EditUserModel Edited, User DBUser)> res = new List<(EditUserModel Edited, User DBUser)>(editUsers.Count());
            var groups = UOW.Repo_Group.All_List;

            foreach (var elem in editUsers)
            {
                var current_groups_id = elem.Groups.
                    Where(g => g.EnterInGroup).
                    Select(g => g.ID);

                User current_user = null;

                switch (elem.Changes)
                {
                    case EnumChanges.Create:
                        current_user = new User(elem.Name, elem.Password, elem.Active,
                            groups.Where(e => current_groups_id.Contains(e.ID)));
                        break;
                    case EnumChanges.Update:
                        current_user = UOW.Repo_User.All.
                            FirstOrDefault(e => e.ID == elem.ID);
                        current_user.Login = elem.Name;
                        current_user.Password = string.IsNullOrEmpty(elem.Password)
                            ? current_user.Password
                            : elem.Password;
                        current_user.IsActive = elem.Active;
                        current_user.Groups = new List<Group>(groups.
                            Where(e => current_groups_id.Contains(e.ID)));
                        break;
                    case EnumChanges.Delete:
                        current_user = UOW.Repo_User.All.
                            FirstOrDefault(e => e.ID == elem.ID);
                        break;
                }

                res.Add(new ValueTuple<EditUserModel, User>(elem, current_user));
            }

            return res;
        }


        public List<EditGroupModel> GroupToGroupEditor()
        {
            var groups = UOW.Repo_Group.
                GetGroupWithDirectory(UOW.Repo_Group.All_List);

            return groups.Select(e => new EditGroupModel()
            {
                ID = e.ID,
                Name = e.Name,
                RootDirs = e.DirectoryPermissions.Permissions.
                    Select(e2 => new RootDirInfo()
                    {
                        ID = e2.Value.DirectoryID,
                        Name = e2.Value.RootDirectory.Name,

                        CanDownload = e2.Value.CanDownload,
                        CanOpen = e2.Value.CanOpen,
                        CanUpload = e2.Value.CanUpload
                    }).ToList()
            }).ToList();
        }
        public List<(EditGroupModel Edited, Group DB)> EditGroupToGroup_List(List<EditGroupModel> editGroup)
        {
            List<(EditGroupModel Edited, Group DB)> res = new List<(EditGroupModel Edited, Group DB)>(editGroup.Count());
            var groups = UOW.Repo_Group.All_List;

            foreach (var elem in editGroup)
            {
                //var current_groups_id = elem.Groups.
                //    Where(g => g.EnterInGroup).
                //    Select(g => g.ID);

                Group current_group = null;

                switch (elem.Changes)
                {
                    case EnumChanges.Create:
                        current_group = new Group() {Name = elem.Name};
                        elem.RootDirs.ForEach(e2 =>
                        {
                            current_group.DirectoryPermissions.AddOrUpdate(new Permission()
                            {
                                CanUpload = e2.CanUpload,
                                CanDownload = e2.CanDownload,
                                CanOpen = e2.CanOpen,
                                DirectoryID = e2.ID
                            });
                        });

                        break;
                    case EnumChanges.Update:
                        current_group = UOW.Repo_Group.All.
                            FirstOrDefault(e => e.ID == elem.ID);
                        current_group.Name = elem.Name;

                        elem.RootDirs.ForEach(e2 => 
                        {
                            current_group.DirectoryPermissions.AddOrUpdate(new Permission()
                            {
                                CanUpload = e2.CanUpload,
                                CanDownload = e2.CanDownload,
                                CanOpen = e2.CanOpen,
                                DirectoryID = e2.ID
                            });
                        });

                        break;
                    case EnumChanges.Delete:
                        current_group = UOW.Repo_Group.All.
                            FirstOrDefault(e => e.ID == elem.ID);
                        break;
                }

                res.Add(new ValueTuple<EditGroupModel, Group>(elem, current_group));
            }

            return res;
        }



        public UserInfoModel GetUserInfo(User user, bool WithPassword = false, bool WithPermission = false)
        {
            var RootDirs = UOW.Repo_SRootDirectory.All_NoTrack_List;

            return new UserInfoModel()
            {
                Login = user.Login,
                Password = WithPassword
                ? user.Password
                : "",
                IsAdmin = user.IsAdmin,
                RootDirs = WithPermission
                ? RootDirs.Select(e => new RootDirInfo()
                {
                    ID = e.ID,
                    Name = e.Name,
                    CanDownload = permissionServices.CanDownload(user, e),
                    CanOpen = permissionServices.CanOpen(user, e),
                    CanUpload = permissionServices.CanUpload(user, e)
                }
                ).ToList()
                : new List<RootDirInfo>()
            };
        }
    }
}
