using Hotline.Caching.Interfaces;
using Hotline.CallCenter.Devices;
using Hotline.CallCenter.Tels;
using Hotline.Share.Dtos.Users;
using MapsterMapper;
using Hotline.CallCenter.Configs;
using Microsoft.Extensions.Options;
using XF.Domain.Authentications;
using XF.Domain.Cache;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;
using XF.Domain.Repository;
using Microsoft.Extensions.DependencyInjection;
using Hotline.Configurations;

namespace Hotline.Users
{
    public class UserDomainService : IUserDomainService, IScopeDependency
    {
        private readonly IRepository<User> _userRepository;
        private readonly IWorkRepository _workRepository;
        private readonly INewRockDeviceManager _newRockDeviceManager;
        private readonly IUserCacheManager _userCacheManager;
        private readonly ITelCacheManager _telCacheManager;
        private readonly ITypedCache<Work> _cacheWork;
        private readonly IMapper _mapper;
        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
        private readonly ISessionContext _sessionContext;
        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
        private readonly IOptionsSnapshot<CallCenterConfiguration> _callcenterOptions;


        public UserDomainService(
            IServiceProvider serviceProvider,
            IRepository<User> userRepository,
            IWorkRepository workRepository,
            ITypedCache<Work> cacheWork,
            IUserCacheManager userCacheManager,
            IMapper mapper,
            ITelCacheManager telCacheManager,
            ISystemSettingCacheManager systemSettingCacheManager,
            ISessionContext sessionContext,
            IOptionsSnapshot<AppConfiguration> appOptions,
            IOptionsSnapshot<CallCenterConfiguration> callcenterOptions)
        {
            _userRepository = userRepository;
            _workRepository = workRepository;
            _userCacheManager = userCacheManager;
            _cacheWork = cacheWork;
            _mapper = mapper;
            _telCacheManager = telCacheManager;
            _systemSettingCacheManager = systemSettingCacheManager;
            _sessionContext = sessionContext;
            _appOptions = appOptions;
            _callcenterOptions = callcenterOptions;
            if (appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XunShi)
            {
                _newRockDeviceManager = serviceProvider.GetRequiredService<INewRockDeviceManager>();
            }
        }

        /// <summary>
        /// 上班
        /// </summary>
        /// <param name="userId">userId</param>
        /// <param name="tel"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task OnDutyAsync(string userId, Tel tel, CancellationToken cancellationToken)
        {
            var user = await _userRepository.GetAsync(userId, cancellationToken);
            if (user is null)
                throw UserFriendlyException.SameMessage("无效的用户编号");

            var workingTel = await _workRepository.GetCurrentWorkByUserAsync(userId, cancellationToken);
            if (workingTel is not null)
                throw UserFriendlyException.SameMessage($"当前用户已上班，userId:{userId}");

            var telIsWorking = await _workRepository.AnyAsync(d => d.TelId == tel.Id && !d.EndTime.HasValue, cancellationToken);
            if (telIsWorking)
                throw UserFriendlyException.SameMessage("当前分机已被占用");

            var work = new Work(userId, user.Name, tel.Id, tel.No);
            await _workRepository.AddAsync(work, cancellationToken);

            if (!string.IsNullOrEmpty(user.StaffNo))
                await _newRockDeviceManager.UpdateStaffNoAsync(_callcenterOptions.Value.NewRock, tel.No, user.StaffNo, tel.LineId, cancellationToken);

            //更新分机组
            foreach (var group in tel.Groups)
            {
                await _newRockDeviceManager.AssginConfigGroupAsync(_callcenterOptions.Value.NewRock, group.No, group.Distribution, new List<string>() { tel.No }, group.Voice, cancellationToken);
            }


        }

        /// <summary>
        /// 下班
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<WorkDto?> OffDutyAsync(string userId, CancellationToken cancellationToken)
        {
            var work = _userCacheManager.GetWorkByUser(userId);
            var tel = _telCacheManager.GetTel(work.TelNo);
            work.OffDuty();
            await _workRepository.UpdateAsync(work, cancellationToken);
            await _newRockDeviceManager.UpdateStaffNoAsync(_callcenterOptions.Value.NewRock, work.TelNo, string.Empty, tel.LineId, cancellationToken);
            _cacheWork.Remove(work.GetKey(KeyMode.UserId));
            _cacheWork.Remove(work.GetKey(KeyMode.TelNo));
            #region 初始化话机

            //初始化解除静音
            await _newRockDeviceManager.UnMuteAsync(_callcenterOptions.Value.NewRock, tel.No, cancellationToken);

            foreach (var group in tel.Groups)
            {
                await _newRockDeviceManager.ModifyGroupExtAsync(_callcenterOptions.Value.NewRock, group.No, group.Distribution, group.Voice, "", false, cancellationToken);
            }

            #endregion
            return _mapper.Map<WorkDto>(work);
        }


        #region 添添呼

        /// <summary>
        /// 下班
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task TrOffDutyAsync(string userId, CancellationToken cancellationToken)
        {
            var work = _userCacheManager.GetWorkByUser(userId);
            if(work is null) return;

            work.OffDuty();
            await _workRepository.UpdateAsync(work, cancellationToken);
            _cacheWork.Remove(work.GetKey(KeyMode.UserId));
            _cacheWork.Remove(work.GetKey(KeyMode.TelNo));
        }


        #endregion
    }
}
