using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DotNetCore.CAP;
using Hotline.Application.CallCenter.Calls;
using Hotline.Application.Tels;
using Hotline.Caching.Interfaces;
using Hotline.CallCenter.BlackLists;
using Hotline.CallCenter.Calls;
using Hotline.CallCenter.Tels;
using Hotline.Orders;
using Hotline.Settings;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.CallCenter;
using Hotline.Share.Dtos.Order;
using Hotline.Share.Dtos.TrCallCenter;
using Hotline.Share.Enums.CallCenter;
using Hotline.Share.Enums.Order;
using Hotline.Share.Mq;
using MapsterMapper;
using Microsoft.AspNetCore.Http;
using SqlSugar;
using XF.Domain.Authentications;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.Application.CallCenter
{
    public class TianRunCallApplication : DefaultCallApplication
    {
        private readonly ISessionContext _sessionContext;
        private readonly IRepository<TrCallRecord> _trCallRecordRepository;
        private readonly ITrApplication _trApplication;
        private readonly ITelApplication _telApplication;
        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
        private readonly IMapper _mapper;
        private readonly ICapPublisher _capPublisher;
        private readonly IRepository<TrCallEvaluate> _trCallEvaluateRepository;
        private readonly IOrderVisitDomainService _orderVisitDomainService;
        private readonly IOrderRepository _orderRepository;
        private readonly IRepository<TelActionRecord> _telActionRecordRepository;

        public TianRunCallApplication(
            ISessionContext sessionContext,
            IRepository<TrCallRecord> trCallRecordRepository,
            ITrApplication trApplication,
            ITelApplication telApplication,
            ISystemSettingCacheManager systemSettingCacheManager,
            IMapper mapper,
            ICapPublisher capPublisher,
            IRepository<TrCallEvaluate> trCallEvaluateRepository,
            IOrderVisitDomainService orderVisitDomainService,
            IOrderRepository orderRepository,
            IRepository<TelActionRecord> telActionRecordRepository)
        {
            _sessionContext = sessionContext;
            _trCallRecordRepository = trCallRecordRepository;
            _trApplication = trApplication;
            _telApplication = telApplication;
            _systemSettingCacheManager = systemSettingCacheManager;
            _mapper = mapper;
            _capPublisher = capPublisher;
            _trCallEvaluateRepository = trCallEvaluateRepository;
            _orderVisitDomainService = orderVisitDomainService;
            _orderRepository = orderRepository;
            _telActionRecordRepository = telActionRecordRepository;
        }

        /// <summary>
        /// 新增黑名单
        /// </summary>
        public override async Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 删除黑名单
        /// </summary>
        public override async Task RemoveBlackListAsync(string id, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 查询黑名单
        /// </summary>
        public override async Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 签入
        /// </summary>
        public override async Task<TrOnDutyResponseDto> SignInAsync(SignInDto dto, CancellationToken cancellationToken) =>
            await _trApplication.OnSign(_sessionContext.RequiredUserId, dto.TelNo, (ETelModel)dto.TelModelState, cancellationToken);

        /// <summary>
        /// 签出
        /// </summary>
        public override Task SingOutAsync(CancellationToken cancellationToken) =>
            _telApplication.SignOutAsync(_sessionContext.RequiredUserId, cancellationToken);

        public override Task SingOutAsync(string telNo, CancellationToken cancellationToken) =>
            _telApplication.SignOutByTelNoAsync(telNo, cancellationToken);

        public override async Task<string> GetOrSetCallIdAsync(string callNo, CancellationToken cancellationToken)
        {
            return await Task.FromResult(callNo);
        }

        public override async Task<string> PublishVisitRelevanceCallIdAsync(OrderRelevanceCallIdDto dto, CancellationToken cancellationToken)
        {
            return await Task.FromResult(dto.CallId);
        }

        public override async Task OrderVisitRelevanceCallIdAsync(VisitDto dto, CancellationToken cancellationToken)
        {
            return;
        }

        /// <summary>
        /// 查询当前用户的分机状态
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public override Task<TrOnDutyResponseDto> GetTelStateAsync(CancellationToken cancellationToken) =>
            _trApplication.TelState(_sessionContext.RequiredUserId, cancellationToken);


        public override async Task<TrCallRecord?> GetTianrunCallAsync(string callId, CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(callId)) return null;
            var callRecord = await _trCallRecordRepository.GetAsync(
                x => x.OtherAccept == callId && string.IsNullOrEmpty(x.OtherAccept) == false, cancellationToken);
            return callRecord;
        }



        /// <summary>
        /// 根据转写ID获取通话信息
        /// </summary>
        /// <returns></returns>
        public override async Task<TrCallRecord?> GetTianrunCallTransliterationAsync(string transliterationId, CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(transliterationId)) return null;
            var callRecord = await _trCallRecordRepository.GetAsync(
                x => x.TransliterationId == transliterationId && string.IsNullOrEmpty(x.OtherAccept) == false, cancellationToken);
            return callRecord;
        }

        /// <summary>
        /// 修改转写状态
        /// </summary>
        /// <returns></returns>
        public override async Task EditTransliterationStateAsync(string callId, ECallTransliterationState state, string transliterationId, CancellationToken cancellationToken)
        {
            await _trCallRecordRepository.Updateable().SetColumns(o => new TrCallRecord { TransliterationState = state, TransliterationId = transliterationId })
                .Where(o => o.Id == callId).ExecuteCommandAsync(cancellationToken);
        }

        /// <summary>
        /// 关联通话记录与order（添润）
        /// </summary>
        public override async Task RelateTianrunCallWithOrderAsync(string callId, string orderId, CancellationToken cancellationToken)
        {
            var callRecords = await _trCallRecordRepository.Queryable().Where(p => p.OtherAccept == callId && string.IsNullOrEmpty(p.OtherAccept) == false).ToListAsync(cancellationToken);

            if (callRecords.Any())
            {
                foreach (var callRecord in callRecords)
                {
                    if (callRecord != null && string.IsNullOrEmpty(callRecord.ExternalId))
                    {
                        callRecord.ExternalId = orderId;
                        callRecord.CallOrderType = Share.Enums.CallCenter.ECallOrderType.Order;
                        await _trCallRecordRepository.UpdateAsync(callRecord, cancellationToken);
                    }
                }
            }
            else
            {
                //如果没查到通话记录就在2分钟后处理
                _capPublisher.PublishDelay(DateTime.Now.AddMinutes(2) - DateTime.Now, EventNames.OrderRelateCall, orderId);
            }
        }

        /// <summary>
        /// 处理工单和通话记录关联问题
        /// </summary>
        /// <param name="orderId"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public override async Task<string> OrderRelateCallHandlerAsync(string orderId, CancellationToken cancellationToken)
        {
            var order = await _orderRepository.GetAsync(orderId, cancellationToken);
            if (order != null)
            {
                var callRecords = await _trCallRecordRepository.Queryable().Where(p => p.OtherAccept == order.CallId && string.IsNullOrEmpty(p.OtherAccept) == false).ToListAsync(cancellationToken);
                if (callRecords.Any())
                {
                    foreach (var callRecord in callRecords)
                    {
                        if (callRecord != null && string.IsNullOrEmpty(callRecord.ExternalId))
                        {
                            callRecord.ExternalId = orderId;
                            callRecord.CallOrderType = Share.Enums.CallCenter.ECallOrderType.Order;
                            await _trCallRecordRepository.UpdateAsync(callRecord, cancellationToken);
                        }
                    }
                }
            }
            return "ok";
        }

        /// <summary>
        /// 查询通话记录
        /// </summary>
        public override async Task<List<TrCallRecord>> QueryTianrunCallsAsync(
            string? phone = null,
            ECallDirection? direction = null,
            DateTime? callStartTimeStart = null,
            DateTime? callStartTimeEnd = null,
            CancellationToken cancellationToken = default)
        {
            return await _trCallRecordRepository.Queryable()
                .WhereIF(!string.IsNullOrEmpty(phone), d => d.CPN == phone || d.CDPN == phone)
                .WhereIF(direction != null, d => d.CallDirection == direction)
                .WhereIF(callStartTimeStart != null, d => d.BeginIvrTime >= callStartTimeStart)
                .WhereIF(callStartTimeEnd != null, d => d.BeginIvrTime <= callStartTimeEnd)
                .OrderBy(x => x.CreatedTime)
                .ToListAsync(cancellationToken);
        }

        /// <summary>
        /// 查询分机操作选项
        /// </summary>
        /// <returns></returns>
        public override List<Kv> GetTelOperationOptions()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 查询通话记录
        /// </summary>
        public override async Task<CallNative?> GetCallAsync(string callId, CancellationToken cancellationToken)
        {
            var call = await _trCallRecordRepository.Queryable()
                .FirstAsync(d => d.OtherAccept == callId, cancellationToken);
            return _mapper.Map<CallNative?>(call);
        }

        /// <summary>
        /// 查询通话记录列表
        /// </summary>
        /// <param name="callId"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public override async Task<List<CallNative>> GetCallListAsync(string callId, CancellationToken cancellationToken)
        {
            var call = await _trCallRecordRepository.Queryable()
                .Where(d => d.OtherAccept == callId).ToListAsync(cancellationToken);
            return _mapper.Map<List<CallNative>>(call);
        }

        /// <summary>
        /// 根据 OrderId 返回用户电话评价枚举
        /// 默认返回 默认满意
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        public override async Task<EVoiceEvaluate> GetReplyVoiceOrDefaultByOrderIdAsync(string orderId)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 根据 OrderId 返回用户电话评价枚举
        ///  默认返回 默认满意
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        public override async Task<ESeatEvaluate> GetSeatDefaultByOrderIdAsync(string orderId)
        {
            var callRecord = await _trCallRecordRepository.Queryable().Where(x => x.ExternalId == orderId && x.CallOrderType == ECallOrderType.Order).FirstAsync();
            if (callRecord is not null)
            {
                var callEvaluate = await _trCallEvaluateRepository.Queryable().Where(x => x.CallAccept == callRecord.CallAccept).FirstAsync();
                if (callEvaluate is null)
                    return ESeatEvaluate.DefaultSatisfied;

                try
                {
                    return (ESeatEvaluate)(Convert.ToInt32(callEvaluate.Dtmf.Trim()));
                }
                catch (UserFriendlyException)
                {
                    return ESeatEvaluate.DefaultSatisfied;
                }
            }
            return ESeatEvaluate.DefaultSatisfied;
        }

        public override async Task ChangeTelModel(bool isCallOut, CancellationToken requestAborted)
        {
            await _trApplication.ChangeTelModel(_sessionContext.RequiredUserId, isCallOut, requestAborted);
        }

        public override ISugarQueryable<TelOperation> QueryTelOperationsAsync(QueryTelOperationsFixedDto dto)
        {
            return _telActionRecordRepository.Queryable()
                .WhereIF(string.IsNullOrEmpty(dto.TelNo) == false, x => x.TelNo.Contains(dto.TelNo))
                .WhereIF(dto.OperateState != null, x => x.ActionType == (EActionType)dto.OperateState)
                .WhereIF(string.IsNullOrEmpty(dto.UserName) == false, x => x.UserName.Contains(dto.UserName))
                .WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
                .WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
                .OrderByDescending(x => x.CreationTime)
                .Select(m => new TelOperation(), true);
        }
    }
}