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

namespace GxPress.Repository.Implement
{
    public class DepartmentRepository : IDepartmentRepository
    {
        private readonly IMapper _mapper;
        private readonly Repository<Department> _repository;
        private readonly Repository<User> _userRepository;

        public DepartmentRepository(IOptionsMonitor<DatabaseOptions> dbOptionsAccessor, IMapper mapper)
        {
            var databaseType = StringUtils.ToEnum<DatabaseType>(dbOptionsAccessor.CurrentValue.DatabaseType, DatabaseType.MySql);
            var database = new Database(databaseType, dbOptionsAccessor.CurrentValue.ConnectionString);
            _repository = 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="parentId"></param>
        /// <returns></returns>
        public async Task<bool> ExistsChildrenAsync(int parentId)
        {
            return await _repository.ExistsAsync(Q.Where(nameof(Department.ParentId), parentId));
        }

        public async Task<Department> GetAsync(int id)
        {
            var department = await _repository.GetAsync(id);
            return department;
        }

        /// <summary>
        /// 根据部门名称查询对应的数据
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public async Task<Department> GetAsync(string name)
        {
            return await _repository.GetAsync(Q.Where(nameof(Department.Name), name));
        }

        public async Task<string> GetNameAsync(int id)
        {
            if (id <= 0) return string.Empty;

            return await _repository.GetAsync<string>(Q
                .Select(nameof(Department.Name))
                .Where(nameof(Department.Id), id)
            );
        }

        public async Task<int> InsertAsync(Department department)
        {
            if (department.Sort > 0)
            {
                var exists = await _repository.ExistsAsync(Q
                    .Where(nameof(Department.Sort), department.Sort)
                );
                if (exists)
                {
                    throw new Exception("部门顺序已存在,请更换");
                }
            }
            return await _repository.InsertAsync(department);
        }

        public async Task<bool> UpdateAsync(Department department)
        {
            if (department.Sort > 0)
            {
                var exists = await _repository.ExistsAsync(Q
                    .WhereNot(nameof(Department.Id), department.Id)
                    .Where(nameof(Department.Sort), department.Sort)
                );
                if (exists)
                {
                    throw new Exception("部门顺序已存在,请更换");
                }
            }

            return await _repository.UpdateAsync(department);
        }

        public async Task<IEnumerable<Department>> GetListAsync(int parentId)
        {
            return await _repository.GetAllAsync(Q.Where(nameof(Department.ParentId), parentId)
                .OrderBy(nameof(Department.Sort)));
        }

        /// <summary>
        /// 排除
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<IEnumerable<Department>> GetListAsync(DepartmentUserRequest request)
        {
            return await _repository.GetAllAsync(Q.Where(nameof(Department.ParentId), request.DepartmentId)
                .WhereNot(nameof(Department.Id), request.SourceDepartmentId));
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<Department> AddAsync(Department request)
        {
            if (request.ParentId > 0)
            {
                var parent = await _repository.GetAsync(request.ParentId);
                if (parent == null) throw new BusinessException("上级部门不存在");
            }

            if (request.LeaderId > 0)
            {
                var leader = await _repository.GetAsync(request.LeaderId);
                if (leader == null) throw new BusinessException("该主管不存在");
            }

            var department = _mapper.Map<Department>(request);

            department.Id = await InsertAsync(department);

            return department;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> DeleteAsync(int id)
        {
            var dep = await _repository.GetAsync(id);
            if (dep == null) throw new BusinessException("该部门不存在");

            if (await ExistsChildrenAsync(id))
                throw new BusinessException("请先删除下级部门");
            //TODO 是否解散部门群
            return await _repository.DeleteAsync(id);
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public async Task<bool> DeleteAsync(SqlKata.Query query)
        {
            return await _repository.DeleteAsync(query) > 0;
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="id"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<bool> UpdateAsync(int id, Department request)
        {
            var dep = await GetAsync(id);
            if (dep == null) throw new BusinessException("该部门不存在");

            dep.LeaderId = request.LeaderId;
            dep.Name = request.Name;
            dep.Sort = request.Sort;

            return await UpdateAsync(dep);
        }

        /// <summary>
        /// 获取树列表
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<List<DepartmentTreeResult>> GetTreeAsync(int id)
        {
            var departments = await GetListAsync(id);

            var list = _mapper.Map<List<DepartmentTreeResult>>(departments);
            foreach (var item in list)
            {
                item.HasChildren = await ExistsChildrenAsync(item.Id);
            }

            return list;
        }

        /// <summary>
        /// 根据部门ID获取成员以及下级部门
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<DepartmentUserResult> GetDepartmentUserResultAsync(DepartmentUserRequest request)
        {
            var result = new DepartmentUserResult();
            var departments = await GetListAsync(request);
            result.Departments = departments;
            var users = await _userRepository.GetAllAsync(Q.Where(nameof(User.DepartmentId), request.DepartmentId));
            result.Users = users.ToList();
            for (int i = 0; i < result.Users.Count(); i++)
            {
                if (!request.IsShow)
                    if (request.UserIds.Contains(result.Users[i].Id))
                        result.Users.Remove(result.Users[i]);
                if (request.IsShow)
                    if (request.UserIds.Contains(result.Users[i].Id))
                        result.Users[i].IsDisable = true;
            }
            foreach (var user in result.Users)
                user.AvatarUrl = StringUtils.AddDomainMin(user.AvatarUrl);
            return result;
        }

        /// <summary>
        /// 获取所用下级部门
        /// </summary>
        /// <param name="id"></param>
        /// <param name="departments"></param>
        /// <returns></returns>
        public async Task<List<Department>> GetDepartmentById(int id, List<Department> departments)
        {
            var department = await _repository.GetAsync(id);
            if (department != null)
            {
                departments.Add(department);
                var list = await _repository.GetAllAsync(Q.Where(nameof(Entity.Department.ParentId), department.Id));
                foreach (var item in list)
                {
                    departments.Add(item);
                    await GetDepartmentById(item.Id, departments);
                }
            }
            return departments;
        }

        /// <summary>
        /// 获取所用下级部门
        /// </summary>
        /// <param name="id"></param>
        /// <param name="departments"></param>
        /// <returns></returns>
        public async Task<List<Department>> GetDepartmentByPid(int Pid, List<Department> departments)
        {
            var departmentList = await _repository.GetAllAsync(Q.Where(nameof(Entity.Department.ParentId), Pid));
            if (departmentList.Count == 0)
                return departments;
            foreach (var item in departmentList)
            {
                departments.Add(item);
                await GetDepartmentByPid(item.Id, departments);
            }
            return departments;
        }
        /// <summary>
        /// 根据部门ID获取全名称
        /// </summary>
        /// <param name="departmentId"></param>
        /// <param name="departmentName"></param>
        /// <returns></returns>
        public async Task<string> GetDepartmentFullPathAsync(int departmentId, string departmentName)
        {
            var department = await _repository.GetAsync(departmentId);
            if (department == null)
            {
                return departmentName;
            }

            if (string.IsNullOrEmpty(departmentName))
                departmentName = department.Name;
            else
                departmentName = department.Name + "/" + departmentName;
            return await GetDepartmentFullPathAsync(department.ParentId, departmentName);

        }

        public async Task<IEnumerable<Department>> GetAllAsync(SqlKata.Query query)
        {
            return await _repository.GetAllAsync(query);
        }
    }
}