using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Repository.Data;
using Siger.Middlelayer.Repository.Entities;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Paged;
using Siger.Middlelayer.Repository.Repositories.Interface;
using Siger.Middlelayer.Repository.Request;
using Siger.Middlelayer.Utility.ImportEntities;

namespace Siger.Middlelayer.Repository.Repositories
{
    internal class SigerUserRepository : ApiConfigRepositoryBase<siger_user>,ISigerUserRepository
    {
        private readonly ApiConfigDbContext _context;
        public SigerUserRepository(ApiConfigDbContext context) : base(context)
        {
            _context = context;
        }

        public IPagedCollectionResult<AdminUser> GetAdmins(int userType, int page, int pagesize)
        {
            var query = _context.siger_user.Where(q => q.status == (int)RowState.Valid && q.type == userType);
            var queryList = from q in query
                join c in _context.siger_user_roles on q.roleid equals c.id
                where c.status == (int) RowState.Valid
                select new AdminUser
                {
                    id = q.id,
                    email = q.email,
                    nickname = q.nickname,
                    rolename = c.name
                };

            var totalCount = queryList.Count();
            var list = queryList.OrderBy(q => q.id).Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();
            return new PagedCollectionResult<AdminUser>(list, totalCount);
        }

        public IPagedCollectionResult<ProjectUser> GetPagedUsers(int sectionid, int usergroupid, string name, int gender, string work_code,
            int projectid, int page, int pagesize)
        {
            var query = _context.siger_project_user.Where(q => q.status == (int)RowState.Valid && q.projectid == projectid && q.sectionid > 0);
            var queryList = from q in query
                            join c in _context.siger_project_section on q.sectionid equals c.id into group1
                            from c in group1.DefaultIfEmpty()
                            join u1 in _context.siger_project_usergroup on q.usergroupid equals u1.id.ToString() into user1
                            from u1 in user1.DefaultIfEmpty()
                            select new ProjectUser
                            {
                                id = q.mid,
                                create_time = q.create_time.ToString(),
                                fixed_line = q.fixed_line,
                                mobile = q.mobile,
                                name = q.name,
                                sectionid = q.sectionid,
                                sectiontitle = (c != null && c.status == (int)RowState.Valid) ? c.title : "",
                                gender = q.sex,
                                sex = q.sex == (int)Gender.male ? "男" : "女",
                                usergroupid = (u1 != null && u1.status == (int)RowState.Valid) ? u1.id : 0,
                                usergrouptitle = (u1 != null && u1.status == (int)RowState.Valid) ? u1.title : "",
                                work_code = q.work_code,
                                work_email = q.work_email,
                                rank = q.rank,
                            };

            Expression<Func<ProjectUser, bool>> sectionidExpression = q => true;
            if (sectionid != 0)
            {
                sectionidExpression = q => q.sectionid == sectionid;
            }
            Expression<Func<ProjectUser, bool>> usergroupidExpression = q => true;
            if (usergroupid != 0)
            {
                usergroupidExpression = q => q.usergroupid == usergroupid;
            }
            Expression<Func<ProjectUser, bool>> nameExpression = q => true;
            if (!string.IsNullOrEmpty(name))
            {
                nameExpression = q => q.name.Contains(name);
            }
            Expression<Func<ProjectUser, bool>> sexExpression = q => true;
            if (gender != 0)
            {
                sexExpression = q => q.gender == gender;
            }
            Expression<Func<ProjectUser, bool>> workcodeExpression = q => true;
            if (!string.IsNullOrEmpty(work_code))
            {
                workcodeExpression = q => q.work_code.Contains(work_code);
            }

            var predicate = sectionidExpression.And(usergroupidExpression).And(nameExpression).And(sexExpression)
                .And(workcodeExpression);

            var totalCount = queryList.Count(predicate);
            var entities = queryList.Where(predicate).OrderBy(q => q.id).Skip((page - 1) * pagesize).Take(pagesize).AsNoTracking().ToList();

            return new PagedCollectionResult<ProjectUser>(entities, totalCount);
        }

        public CommonImportResult ImportUsers(IEnumerable<UserList> users, int projectid)
        {
            var errors = new List<string>();
            var entities = new List<siger_project_user>();
            var rowIndex = 1;
            var role_id = 0;

            var moblieduplicate = new List<string>();
            var workduplicate = new List<string>();

            foreach (var user in users)
            {
                rowIndex++;
                var section = _context.siger_project_section.FirstOrDefault(q => q.title == user.Section && q.projectid == projectid && q.status == (int)RowState.Valid);
                if (section == null)
                {
                    errors.Add($"{rowIndex},{Convert.ToString((int)RequestEnum.SectionNotFound)}");
                }
                else
                {
                    var usergroup = _context.siger_project_usergroup.FirstOrDefault(q => q.title == user.Usergroup && q.projectid == projectid && q.sectionid == section.id && q.status == (int)RowState.Valid);
                    if (usergroup == null)
                    {
                        errors.Add($"{rowIndex},{Convert.ToString((int)RequestEnum.UserGroupNotFound)}");
                    }
                    role_id = usergroup == null ? 0 : usergroup.role_id ?? 0;
                }

                if (!string.IsNullOrEmpty(user.Mobile))
                {
                    if (moblieduplicate.Contains(user.Mobile))
                    {
                        errors.Add($"{rowIndex},{Convert.ToString((int)RequestEnum.MobileHasExist)}");
                    }
                    var isExist = _context.siger_user.FirstOrDefault(q => q.mobile == user.Mobile && q.status == (int)RowState.Valid);
                    if (isExist != null)
                    {
                        errors.Add($"{rowIndex},{Convert.ToString((int)RequestEnum.MobileHasExist)}");
                    }
                    moblieduplicate.Add(user.Mobile);
                }
                else
                {
                    errors.Add($"{rowIndex},{Convert.ToString((int)RequestEnum.MobileIsEmpty)}");
                }
                if (!string.IsNullOrEmpty(user.Work_code))
                {
                    if (workduplicate.Contains(user.Work_code))
                    {
                        errors.Add($"{rowIndex},{Convert.ToString((int)RequestEnum.WorkcodeHasExist)}");
                    }
                    var isExist = _context.siger_project_user.FirstOrDefault(q => q.work_code == user.Work_code && q.projectid == projectid
                                                                                  && q.status == (int)RowState.Valid);
                    if (isExist != null)
                    {
                        errors.Add($"{rowIndex},{Convert.ToString((int)RequestEnum.WorkcodeHasExist)}");
                    }
                    workduplicate.Add(user.Work_code);
                }
                else
                {
                    errors.Add($"{rowIndex},{Convert.ToString((int)RequestEnum.WorkCodeIsEmpty)}");
                }

                if (errors.Any())
                {
                    return new CommonImportResult(0, string.Join(";", errors));
                }
            }
            //add record
            foreach (var user in users)
            {
                var section = _context.siger_project_section.First(q => q.title == user.Section && q.projectid == projectid && q.status == (int)RowState.Valid);
                var usergroup = _context.siger_project_usergroup.First(q => q.title == user.Usergroup && q.projectid == projectid && q.sectionid == section.id && q.status == (int)RowState.Valid);
                var entityUser = new siger_user
                {
                    nickname = user.Name,
                    sex = user.Sex == "男" ? (int)Gender.male : (int)Gender.female,
                    mobile = user.Mobile,
                    email = user.Email,
                    roleid = role_id,
                    type = (int)UserType.User,
                    password = MD5Helper.Get32MD5(string.IsNullOrWhiteSpace(user.Password) ? "123456" : user.Password),
                };
                _context.siger_user.Add(entityUser);
                _context.SaveChanges();

                int inJobDate = 0;
                if (!string.IsNullOrWhiteSpace(user.Create_time))
                {
                    var success = DateTime.TryParse(user.Create_time, out var inDate);
                    if (success)
                    {
                        inJobDate = (int)UnixTimeHelper.ConvertDataTimeLong(inDate);
                    }
                }
                else
                {
                    inJobDate = (int)UnixTimeHelper.ConvertDataTimeLong(DateTime.Now);
                }

                var entityProjectUser = new siger_project_user
                {
                    mid = entityUser.id,
                    name = user.Name,
                    sex = entityUser.sex,
                    sectionid = section.id,
                    usergroupid = usergroup.id.ToString(),
                    mobile = user.Mobile,
                    fixed_line = user.Fixed_line,
                    work_email = user.Email,
                    work_code = user.Work_code,
                    create_time = inJobDate,
                    projectid = projectid,
                    rank = user.Rank
                };
                entities.Add(entityProjectUser);

            }

            try
            {
                _context.siger_project_user.AddRange(entities);
                _context.SaveChanges();
                return new CommonImportResult(1, "1");
            }
            catch
            {
                throw;
            }
        }

        public IList<ProjectUser> ExportUsers(int sectionid, int usergroupid, string name, int sex, string work_code,
            int projectid)
        {
            var query = _context.siger_project_user.Where(q => q.status == (int)RowState.Valid && q.projectid == projectid);
            var queryList = from q in query
                            join c in _context.siger_project_section on q.sectionid equals c.id into group1
                            from c in group1.DefaultIfEmpty()
                            where c.status == (int)RowState.Valid
                            join u1 in _context.siger_project_usergroup on q.usergroupid equals u1.id.ToString() into user1
                            from u1 in user1.DefaultIfEmpty()
                            where u1.status == (int)RowState.Valid
                            select new ProjectUser
                            {
                                id = q.mid,
                                create_time = q.create_time.ToString(),
                                fixed_line = q.fixed_line,
                                mobile = q.mobile,
                                name = q.name,
                                sectionid = q.sectionid,
                                sectiontitle = c != null ? c.title : "",
                                sex = q.sex == (int)Gender.male ? "男" : "女",
                                gender = q.sex,
                                usergroupid = u1 != null ? u1.id : 0,
                                usergrouptitle = u1 != null ? u1.title : "",
                                work_code = q.work_code,
                                work_email = q.work_email,
                                rank = q.rank
                            };

            Expression<Func<ProjectUser, bool>> sectionidExpression = q => true;
            if (sectionid != 0)
            {
                sectionidExpression = q => q.sectionid == sectionid;
            }
            Expression<Func<ProjectUser, bool>> usergroupidExpression = q => true;
            if (usergroupid != 0)
            {
                usergroupidExpression = q => q.usergroupid == usergroupid;
            }
            Expression<Func<ProjectUser, bool>> nameExpression = q => true;
            if (!string.IsNullOrEmpty(name))
            {
                nameExpression = q => q.name.Contains(name);
            }
            Expression<Func<ProjectUser, bool>> sexExpression = q => true;
            if (sex != 0)
            {
                sexExpression = q => q.gender == sex;
            }
            Expression<Func<ProjectUser, bool>> workcodeExpression = q => true;
            if (!string.IsNullOrEmpty(work_code))
            {
                workcodeExpression = q => q.work_code.Contains(work_code);
            }

            var predicate = sectionidExpression.And(usergroupidExpression).And(nameExpression).And(sexExpression)
                .And(workcodeExpression);

            var entities = queryList.Where(predicate).AsNoTracking().ToList();

            return entities;
        }

        public bool CheckShiftTimes(List<TimeCompare> times, int sectionid, int departid)
        {
            var now = UnixTimeHelper.GetNow();
            var compareTimes = new List<long>();
            foreach (var timeCompare in times)
            {
                compareTimes.Add(UnixTimeHelper.ConvertDataTimeLong(timeCompare.StartTime));
                compareTimes.Add(UnixTimeHelper.ConvertDataTimeLong(timeCompare.EndTime));
            }

            foreach (var compareTime in compareTimes)
            {
                var query = _context.siger_project_station.Where(q => q.sectionid == sectionid && q.departid == departid
                                                                                               && q.starttime <= compareTime && q.endtime >= compareTime
                                                                                               && q.endtime <= now);
                if (query.Any())
                {
                    return false;
                }
            }

            return true;
        }

        public IEnumerable<siger_user_power> GetUserPowers(int userId, int projectId)
        {
            var user = _context.siger_user.FirstOrDefault(q => q.id == userId && q.status == (int)RowState.Valid);
            if (user == null)
            {
                return new List<siger_user_power>();
            }

            if (user.type == (int) UserType.SuperAdmin)
            {
                return _context.siger_user_power.Where(q => q.status == (int)RowState.Valid).OrderBy(q => q.id);
            }

            if (user.type == (int)UserType.Admin) // 管理员取项目类型的菜单
            {
                var query = from p in _context.siger_project
                    join t in _context.siger_project_type on p.typeid equals t.id
                    where p.id == projectId
                    select t.id;
                if (query.Any())
                {
                    var projectTypeId = query.First();
                    var projectTypePowers = _context.siger_user_role_power
                        .Where(q => q.roleid == projectTypeId && q.status == (int)RowState.Valid)
                        .Select(m => m.powerid).ToList();
                    if (projectTypePowers.Any())
                    {
                        return _context.siger_user_power.Where(q => projectTypePowers.Contains(q.id) && q.status == (int)RowState.Valid)
                            .OrderBy(q => q.sorting).ThenBy(q => q.id);
                    }
                }
            }
            else
            {
                var usergroup = from p in _context.siger_project_user
                    join ug in _context.siger_project_usergroup on p.usergroupid equals ug.id.ToString()
                    where p.mid == userId && p.projectid == projectId
                    select ug;
                if (usergroup.FirstOrDefault() != null)
                {
                    var roleId = usergroup.First().role_id.ToStr().ToInt();
                    var powers = _context.siger_user_role_power
                        .Where(q => q.roleid == roleId && q.status == (int)RowState.Valid)
                        .Select(m => m.powerid).ToList();
                    if (!powers.Any())
                    {
                        return new List<siger_user_power>();
                    }
                    return _context.siger_user_power.Where(q => powers.Contains(q.id) && q.status == (int)RowState.Valid)
                        .OrderBy(q => q.sorting).ThenBy(q => q.id);
                }
            }
            return new List<siger_user_power>();
        }

        protected IEnumerable<siger_user_power> GetSonLevelPowers(string parentId)
        {
            var query = from c in _context.siger_user_power
                        where c.parent == parentId  && c.status == (int)RowState.Valid
                select c;

            return query.ToList().Concat(query.ToList().SelectMany(t => GetSonLevelPowers(t.id.ToString())));
        }

        public IEnumerable<siger_user_power> GetModulePowers(int userId, int projectId, string parent)
        {
            var user = _context.siger_user.FirstOrDefault(q => q.id == userId && q.status == (int)RowState.Valid);
            if (user == null)
            {
                return new List<siger_user_power>();
            }

            if (user.type == (int) UserType.SuperAdmin)
            {
                var list = new List<int>{parent.ToInt()};
                var query = GetSonLevelPowers(parent);
                foreach (var power in query.ToList())
                {
                    list.Add(power.id);
                }
                var queryList = from q in _context.siger_user_power
                    where q.status == (int) RowState.Valid && list.Contains(q.id)
                    select q;
                return queryList.OrderBy(q => q.id).AsEnumerable();
            }

            if (user.type == (int) UserType.Admin) // 管理员取项目类型的菜单
            {
                var query = from p in _context.siger_project
                    join t in _context.siger_project_type on p.typeid equals t.id
                    where p.id == projectId
                    select t.id;

                var projectTypeId = query.First();
                var projectTypePowers = _context.siger_user_role_power
                    .Where(q => q.roleid == projectTypeId && q.status == (int) RowState.Valid)
                    .Select(m => m.powerid).ToList();

                return _context.siger_user_power
                    .Where(q => projectTypePowers.Contains(q.id) && q.status == (int) RowState.Valid)
                    .OrderBy(q => q.sorting).ThenBy(q => q.id);
            }

            var usergroup = from p in _context.siger_project_user
                join ug in _context.siger_project_usergroup on p.usergroupid equals ug.id.ToString()
                where p.mid == userId && p.projectid == projectId
                select ug;
            if (usergroup.FirstOrDefault() != null)
            {
                var roleId = usergroup.First().role_id.ToStr().ToInt();
                var powers = _context.siger_user_role_power
                    .Where(q => q.roleid == roleId && q.status == (int)RowState.Valid)
                    .Select(m => m.powerid).ToList();
                if (!powers.Any())
                {
                    return new List<siger_user_power>();
                }
                return _context.siger_user_power.Where(q => powers.Contains(q.id) && q.status == (int)RowState.Valid)
                    .OrderBy(q => q.sorting).ThenBy(q => q.id);
            }

            return new List<siger_user_power>();
        }

        public IEnumerable<siger_user_power> GetAppPowers(int userId, int projectId)
        {
            var user = _context.siger_user.FirstOrDefault(q => q.id == userId && q.status == (int) RowState.Valid);
            if (user == null)
            {
                return new List<siger_user_power>();
            }
            var powers = _context.siger_user_role_power
                .Where(q => q.roleid == user.roleid && q.status == (int)RowState.Valid)
                .Select(m => m.powerid).ToList();

            var responses = new List<siger_user_power>();

            var parents = _context.siger_user_power.Where(q => powers.Contains(q.id) && q.status == (int)RowState.Valid && q.parent == "0")
                .OrderBy(q => q.id);
            foreach (var power in parents.ToList())
            {
                responses.Add(power);

                responses.AddRange(_context.siger_user_power.Where(q =>
                    q.parent == power.id.ToString() && q.type == (int) PowerType.App &&
                    q.status == (int) RowState.Valid).OrderBy(q => q.sorting).ToList());
            }

            return responses;
        }
    }
}
