using Hotline.Application.CallCenter;
using Quartz;
using SqlSugar;
using Hotline.CallCenter.Calls;
using Hotline.Repository.SqlSugar;
using Hotline.Users;
using MapsterMapper;
using Microsoft.Extensions.Logging;
using XF.Domain.Repository;
using XingTang.Sdk;

namespace Hotline.Application.Jobs
{
    /// <summary>
    /// 查询兴唐通话记录
    /// </summary>
    public class XingTangCallsSyncJob : IJob, IDisposable
    {
        private readonly IRepository<CallNative> _callRepository;
        private readonly IRepository<User> _userRepository;
        private readonly ICallApplication _callApplication;
        private readonly IMapper _mapper;
        private readonly ILogger<XingTangCallsSyncJob> _logger;
        private readonly ISqlSugarClient _db;

        public XingTangCallsSyncJob(
            ISugarUnitOfWork<XingTangDbContext> uow,
            IRepository<CallNative> callRepository,
            IRepository<User> userRepository,
            ICallApplication callApplication,
            IMapper mapper,
            ILogger<XingTangCallsSyncJob> logger)
        {
            _callRepository = callRepository;
            _userRepository = userRepository;
            _callApplication = callApplication;
            _mapper = mapper;
            _logger = logger;
            _db = uow.Db;
        }

        public async Task Execute(IJobExecutionContext context)
        {
            var xingtangCalls = await _db.Queryable<XingtangCall>()
                .Where(d => (d.IsSync == null || !d.IsSync) && (d.Tries == null || d.Tries <= 50))
                .OrderBy(d => d.Id)
                .Take(10)
                .ToListAsync(context.CancellationToken);

            var occupyCalls = new List<XingtangCall>();
            foreach (var call in xingtangCalls)
            {
                call.IsSync = true;
                call.Tries += 1;

                var rows = await _db.Updateable(call)
                    .ExecuteCommandWithOptLockAsync();
                if (rows > 0)
                    occupyCalls.Add(call);
            }

            try
            {
                var calls = _mapper.Map<List<CallNative>>(occupyCalls);
                //填充user信息
                var staffNos = calls.Select(d => d.StaffNo).ToList();
                var users = await _userRepository.Queryable()
                    .Where(d => staffNos.Contains(d.StaffNo))
                    .ToListAsync(context.CancellationToken);

                foreach (var call in calls)
                {
                    call.Id = await GetCallIdAsync(call.CallNo, context.CancellationToken);
                    var user = users.FirstOrDefault(d => d.StaffNo == call.StaffNo);
                    if (user is not null)
                    {
                        call.UserId = user.Id;
                        call.UserName = user.Name;
                    }
                }

                await _callRepository.AddRangeAsync(calls, context.CancellationToken);
            }
            catch (Exception e)
            {
                //Console.WriteLine(e);
                _logger.LogError($"获取通话记录异常：{e.Message} \n {e.StackTrace}");
                foreach (var occupyCall in occupyCalls)
                {
                    occupyCall.IsSync = false;
                }

                await _db.Updateable(occupyCalls)
                    .UpdateColumns(d => new { d.IsSync })
                    .ExecuteCommandAsync(context.CancellationToken);
            }
        }

        private async Task<string> GetCallIdAsync(string callNo, CancellationToken cancellation)
        {
            var relation = await _callApplication.GetRelationAsync(callNo, cancellation);
            if (relation is null)
            {
                relation = new CallidRelation
                {
                    Id = callNo,
                    CallId = Ulid.NewUlid().ToString(),
                    IsUsed = true
                };
                await _callApplication.AddRelationAsync(relation, cancellation);
                return relation.CallId;
            }

            if (relation.IsUsed)
                return Ulid.NewUlid().ToString();

            relation.IsUsed = true;
            var rows = await _callApplication.UpdateRelationOptLockAsync(relation, cancellation);
            if (rows > 0)
                return relation.CallId;

            //重新取relation 重新判断isUsed
            return await GetCallIdAsync(callNo, cancellation);
        }

        /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
        public void Dispose()
        {
            //_logger.LogInformation($"{nameof(XingTangCallsSyncJob)} disposed");
        }
    }
}