using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Transactions;
using AutoMapper;
using GxPress.Common.AppOptions;
using GxPress.Common.Exceptions;
using GxPress.Common.Tools;
using GxPress.Entity;
using GxPress.Repository.Interface;
using GxPress.Request.AddressBookGroup;
using GxPress.Result.AddressBook;
using Microsoft.Extensions.Options;
using Datory;
using GxPress.Result.AddressBookGroup;
using Dapper;

namespace GxPress.Repository.Implement
{
    public class AddressBookGroupRepository : IAddressBookGroupRepository
    {
        private readonly Repository<AddressBookGroup> _repository;
        private readonly Repository<AddressBookGroupUser> _addressBookGroupUserRepository;
        private readonly Repository<Department> _departmentRepository;
        private readonly Repository<User> _userRepository;
        private readonly IMapper _mapper;
        private readonly string _connectionString;
        private readonly string _databaseTypeStr;
        public AddressBookGroupRepository(IOptionsMonitor<DatabaseOptions> dbOptionsAccessor, IMapper mapper)
        {
            _databaseTypeStr = dbOptionsAccessor.CurrentValue.DatabaseType;
            _connectionString = dbOptionsAccessor.CurrentValue.ConnectionString;
            var databaseType = StringUtils.ToEnum<DatabaseType>(dbOptionsAccessor.CurrentValue.DatabaseType, DatabaseType.MySql);
            var database = new Database(databaseType, dbOptionsAccessor.CurrentValue.ConnectionString);
            _repository = new Repository<AddressBookGroup>(database);
            _addressBookGroupUserRepository = new Repository<AddressBookGroupUser>(database);
            _departmentRepository = new Repository<Department>(database);
            _userRepository = new Repository<User>(database);
            _mapper = mapper;
        }

        public IDatabase Database => _repository.Database;
        public string TableName => _repository.TableName;
        public List<TableColumn> TableColumns => _repository.TableColumns;

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> DeleteAsync(int id)
        {
            //删除组下面的
            await _addressBookGroupUserRepository.DeleteAsync(Q.Where(nameof(AddressBookGroupUser.AddressBookGroupId),
                id));
            return await _repository.DeleteAsync(id);
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<bool> UpdateAsync(AddressBookGroupUpRequest request)
        {
            var addressBookGroup = await _repository.GetAsync(request.AddressBookGroupId);
            addressBookGroup.GroupName = request.GroupName;
            return await _repository.UpdateAsync(addressBookGroup);
        }

        /// <summary>
        /// 获取用户通讯录组
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<IEnumerable<AddressBookGroupResult>> GetAddressBookGroupListAsync(
            AddressBookGroupSearchRequest request)
        {
            var result = await _repository.GetAllAsync(Q.Where(nameof(AddressBookGroup.UserId), request.UserId).Where(nameof(AddressBookGroup.ParentId), request.ParendId).OrderByDesc(nameof(AddressBookGroup.Sort)));
            var addressBookGroupResults = result.Select(n => _mapper.Map<AddressBookGroupResult>(n)).ToList();
            for (int i = 0; i < addressBookGroupResults.Count; i++)
            {
                if (request.FolderIds.Contains(addressBookGroupResults[i].Id))
                    addressBookGroupResults.Remove(addressBookGroupResults[i]);
                else
                {
                    addressBookGroupResults[i].IsChildren = await _repository.ExistsAsync(Q.Where(nameof(AddressBookGroup.UserId), request.UserId).Where(nameof(AddressBookGroup.ParentId), addressBookGroupResults[i].Id));
                }
            }
            return addressBookGroupResults;
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<AddressBookGroup> InsertAsync(AddressBookGroupInRequest request)
        {
            var addressBookGroup = new AddressBookGroup
            {
                GroupName = request.AddressBookGroupName,
                UserId = request.UserId,
                ParentId = request.ParentId
            };
            var id = await _repository.InsertAsync(addressBookGroup);
            addressBookGroup = await _repository.GetAsync(id);
            addressBookGroup.Sort = id;
            await _repository.UpdateAsync(addressBookGroup);
            return addressBookGroup;
        }

        /// <summary>
        /// 获取通讯录用户组
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<AddressBookListResult> GetAddressBookListAsync(AddressBookListRequest request)
        {
            var result = new AddressBookListResult();
            //获取系统分配组
            var departments = await _departmentRepository.GetAllAsync(Q.Where(nameof(Department.ParentId), 0));
            result.Departments = departments.ToList();
            var addressBookGroups =
                await _repository.GetAllAsync(Q.Where(nameof(AddressBookGroup.UserId), request.UserId).OrderByDesc(nameof(AddressBookGroup.Sort)));
            var list = addressBookGroups.ToList();
            result.AddressBookGroups = list;
            return result;
        }
        /// <summary>
        /// 添加通讯录用户
        /// </summary>
        /// <param name="addressBookGroupId"></param>
        /// <param name="addressBookGroupUser"></param>
        /// <returns></returns>
        public async Task<bool> IsInsertAddressBookUserAsync(int addressBookGroupId,
            AddressBookGroupUser addressBookGroupUser)
        {
            if (await _addressBookGroupUserRepository.CountAsync(Q
                    .Where(nameof(AddressBookGroupUser.AddressBookGroupId), addressBookGroupId)
                    .Where(nameof(AddressBookGroupUser.UserId), addressBookGroupUser.UserId)) == 0)
            {
                await _addressBookGroupUserRepository.InsertAsync(addressBookGroupUser);
            }

            return true;
        }

        /// <summary>
        /// 添加联系人
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<bool> InsertAddressBookUserAsync(AddressBookInUserRequest request)
        {
            if (request.AddressBookGroupId <= 0)
            {
                throw new BusinessException("文件ID为空");
            }

            try
            {
                using (TransactionScope transactionScope = new TransactionScope())
                {
                    //添加用户
                    foreach (var userId in request.UserIds)
                    {
                        var addressBookGroupUser = new AddressBookGroupUser
                        {
                            AddressBookGroupId = request.AddressBookGroupId,
                            UserId = userId
                        };
                        //await _addressBookGroupUserRepository.InsertAsync(addressBookGroupUser);
                        await IsInsertAddressBookUserAsync(request.AddressBookGroupId, addressBookGroupUser);
                    }

                    //添加部门人员
                    foreach (var departmentId in request.DepartmentIds)
                    {
                        List<User> users = new List<User>();
                        users = await GetUserByDepartmentIdAsync(users, departmentId);
                        foreach (var user in users)
                        {
                            var addressBookGroupUser = new AddressBookGroupUser
                            {
                                AddressBookGroupId = request.AddressBookGroupId,
                                UserId = user.Id
                            };
                            // await _addressBookGroupUserRepository.InsertAsync(addressBookGroupUser);
                            await IsInsertAddressBookUserAsync(request.AddressBookGroupId, addressBookGroupUser);
                        }
                    }

                    //添加组人员
                    foreach (var addressBookGroupId in request.AddressBookGroupIds)
                    {
                        var addressBookGroupUserList = new List<AddressBookGroupUser>();
                        if (addressBookGroupId == 0)
                        {
                            var addressBookGroupUsers = await _addressBookGroupUserRepository.GetAllAsync();
                            addressBookGroupUserList.AddRange(addressBookGroupUsers);
                        }
                        else
                        {
                            var addressBookGroupUsers = await _addressBookGroupUserRepository.GetAllAsync(
                                Q.Where(nameof(AddressBookGroupUser.AddressBookGroupId), addressBookGroupId));
                            addressBookGroupUserList.AddRange(addressBookGroupUsers);
                        }

                        foreach (var item in addressBookGroupUserList)
                        {
                            var addressBookGroupUser = new AddressBookGroupUser
                            {
                                AddressBookGroupId = request.AddressBookGroupId,
                                UserId = item.UserId
                            };
                            //await _addressBookGroupUserRepository.InsertAsync(addressBookGroupUser);
                            await IsInsertAddressBookUserAsync(request.AddressBookGroupId, addressBookGroupUser);
                        }
                    }

                    transactionScope.Complete();
                }
            }
            catch (Exception e)
            {
                throw new BusinessException(e.Message);
            }

            return true;
        }

        /// <summary>
        /// 递归查询部门下级用户
        /// </summary>
        /// <param name="users"></param>
        /// <param name="departmentId"></param>
        /// <returns></returns>
        public async Task<List<User>> GetUserByDepartmentIdAsync(List<User> users, int departmentId)
        {
            var userList = await _userRepository.GetAllAsync(Q.Where(nameof(User.DepartmentId), departmentId));
            users.AddRange(userList);
            var departments =
                await _departmentRepository.GetAllAsync(Q.Where(nameof(Department.ParentId), departmentId));
            if (departments.Any())
            {
                foreach (var department in departments)
                {
                    await GetUserByDepartmentIdAsync(users, department.Id);
                }

            }

            return users;
        }

        /// <summary>
        /// 根据通讯录PID获取用户
        /// </summary>
        /// <param name="users"></param>
        /// <param name="pid"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<List<User>> GetUserByAddressBookGroupPidAsync(List<User> users, int pid, int userId)
        {
            var addressBookGroups = await _repository.GetAllAsync(Q.Where(nameof(AddressBookGroup.ParentId), pid).Where(nameof(AddressBookGroup.UserId), userId));
            if (!addressBookGroups.Any())
            {
                return users;
            }

            foreach (var addressBookGroup in addressBookGroups)
            {
                var addressBookGroupUsers =
                    await _addressBookGroupUserRepository.GetAllAsync(
                        Q.Where(nameof(AddressBookGroupUser.AddressBookGroupId), addressBookGroup.Id));
                if (!addressBookGroupUsers.Any())
                    continue;
                foreach (var item in addressBookGroupUsers)
                {
                    var user = await _userRepository.GetAsync(item.UserId);
                    users.Add(user);
                }

                await GetUserByAddressBookGroupPidAsync(users, addressBookGroup.Id, userId);
            }

            return users;
        }
        /// <summary>
        /// 根据组ID获取用户
        /// </summary>
        /// <param name="addressBookGroupId"></param>
        /// <returns></returns>
        public async Task<List<User>> GetUserByAddressBookGroupIdAsync(int addressBookGroupId)
        {
            var users = new List<User>();
            var addressBookGroupUserList =
                await _addressBookGroupUserRepository.GetAllAsync(
                    Q.Where(nameof(AddressBookGroupUser.AddressBookGroupId), addressBookGroupId));
            foreach (var item in addressBookGroupUserList)
            {
                var user = await _userRepository.GetAsync(item.UserId);
                users.Add(user);
            }

            return users;
        }

        public async Task<List<AddressBookGroup>> GetAllAsync(SqlKata.Query query)
        {
            return await _repository.GetAllAsync(query);
        }
        /// <summary>
        /// 排序
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<bool> SortAsync(AddressBookGroupSortRequest request)
        {
            var frist = await _repository.GetAsync(request.FristId);
            var last = await _repository.GetAsync(request.LastId);
            if (last != null && frist != null)
            {
                var databaseType = StringUtils.ToEnum<DatabaseType>(_databaseTypeStr, DatabaseType.MySql);
                var database = new Database(databaseType, _connectionString);
                var connection = database.GetConnection();
                if (frist.Sort < last.Sort)
                {
                    //修改last
                    var lessThanSql = $"update tede_address_book_group set Sort=Sort-1 where UserId={request.UserId} and Sort<={last.Sort} and Id>0";
                    if (await connection.ExecuteAsync(lessThanSql) > 0)
                    {
                        //修改sort
                        frist.Sort = last.Sort;
                        await _repository.UpdateAsync(frist);
                        return true;
                    }
                }
                else
                {
                    //修改last
                    var lessThanSql = $"update tede_address_book_group set Sort=Sort+1 where UserId={request.UserId} and Sort>={last.Sort} and Id>0";
                    if (await connection.ExecuteAsync(lessThanSql) > 0)
                    {
                        //修改sort
                        frist.Sort = last.Sort;
                        await _repository.UpdateAsync(frist);
                        return true;
                    }
                }
            }
            return false;
        }
    }
}