using Amazon.Runtime.Internal.Transform;
using DotNetCore.CAP;
using Hotline.Permissions;
using Hotline.Push;
using Hotline.Push.FWMessage;
using Hotline.Repository.SqlSugar.Extensions;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.Push;
using Hotline.Share.Dtos.Push.FWMessage;
using Hotline.Share.Enums.Push;
using Hotline.Share.Mq;
using Hotline.Share.Tools;
using Hotline.Tools;
using Hotline.Users;
using J2N.Text;
using JiebaNet.Segmenter.Common;
using MapsterMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Text;
using XF.Domain.Exceptions;
using XF.Domain.Repository;
using XF.Utility.EnumExtensions;

namespace Hotline.Api.Controllers
{
    public class PushMessageController : OriginController
    {
        #region 注入

        private readonly IRepository<Message> _messageRepository;
        private readonly IMapper _mapper;
        private readonly IPushDomainService _pushDomainService;
        private readonly IMessageCodeDomainService _messageCodeDomainService;
        private readonly IRepository<BatchSmsTask> _batchSmsTaskRepository;
        private readonly IRepository<BatchSmsTaskDetail> _batchSmsTaskDetailRepository;
        private readonly ICapPublisher _capPublisher;
        private readonly IRepository<User> _userRepository;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="messageRepository"></param>
        /// <param name="mapper"></param>
        /// <param name="pushDomainService"></param>
        /// <param name="messageCodeDomainService"></param>
        public PushMessageController(IRepository<Message> messageRepository,
            IMapper mapper,
            IPushDomainService pushDomainService,
            IMessageCodeDomainService messageCodeDomainService,
            IRepository<BatchSmsTask> batchSmsTaskRepository,
            IRepository<BatchSmsTaskDetail> batchSmsTaskDetailRepository,
            ICapPublisher capPublisher,
            IRepository<User> userRepository)
        {
            _messageRepository = messageRepository;
            _mapper = mapper;
            _pushDomainService = pushDomainService;
            _messageCodeDomainService = messageCodeDomainService;
            _batchSmsTaskRepository = batchSmsTaskRepository;
            _batchSmsTaskDetailRepository = batchSmsTaskDetailRepository;
            _capPublisher = capPublisher;
            _userRepository = userRepository;
        }

        #endregion

        /// <summary>
        /// 发送登录验证码
        /// </summary>
        /// <param name="UserName"></param>
        /// <returns></returns>
        [HttpGet("send_login_message_code")]
        [AllowAnonymous]
        public async Task<string> SendLoginMessageCode(string UserName)
        {
            return await _messageCodeDomainService.GenerateVerificationCode(UserName, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 验证白名单
        /// </summary>
        /// <param name="UserName"></param>
        /// <returns></returns>
        [HttpGet("get_verify_whitelist")]
        [AllowAnonymous]
        public async Task<bool> VerifyWhitelist(string UserName)
        {
            return await _messageCodeDomainService.VerifyWhitelistAsync(UserName);
        }

        /// <summary>
        /// 修改短信状态
        /// </summary>
        /// <param name="messageDto"></param>
        /// <param name="cancellation"></param>
        /// <returns></returns>
        [HttpPost("update-send-sms-state")]
        [AllowAnonymous]
        public async Task UpdateSendSmsState(PushReceiveMessageDto messageDto, CancellationToken cancellation)
        {
            await _pushDomainService.PushMsgUpdateStateNewAsync(messageDto, cancellation);
        }

        //[HttpGet("checkdcode")]
        //public async Task CheckdCode(string UserName, string phoneNum, string Code)
        //{
        //    await _messageCodeDomainService.CheckdCode(UserName, phoneNum, Code, HttpContext.RequestAborted);
        //}

        #region 新增

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("add")]
        [AllowAnonymous]
        public async Task AddMessage([FromBody] MessageDto dto)
        {
            //  await _pushDomainService.PushAsync(dto, HttpContext.RequestAborted);
            await _pushDomainService.PushMsgAsync(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 发送短信
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("send")]
        public async Task<string> SendMessage([FromBody] MessageInDto dto)
        {
            dto.ValidateObject();
            if (dto.TelNumbers == null && dto.UserIds == null)
                throw UserFriendlyException.SameMessage("电话号码和用户Id不能同时为空");
            var telNumbers = new List<Kv>();
            if (dto.TelNumbers.NotNullOrEmpty())
                telNumbers = dto.TelNumbers.Split(",").Select(m => new Kv(m, m)).ToList();
            if (dto.UserIds.IsNotEmpty())
                telNumbers = await _userRepository.Queryable()
                    .Where(m => dto.UserIds.Contains(m.Id))
                    .Select(m => new Kv { Key = m.PhoneNo, Value = m.Name })
                    .ToListAsync();
            var count = 0;
            var errorSB = new StringBuilder("失败原因: ");
            var errorCount = 0;
            foreach (var telNumber in telNumbers)
            {
                if (telNumber.Key.IsPhoneNumber() == false)
                {
                    errorCount++;
                    errorSB.Append($" {telNumber}不是合法的手机号码.");
                    continue;
                }

                var inDto = new MessageDto
                {
                    TelNumber = telNumber.Key,
                    Content = dto.Content,
                    PushBusiness = EPushBusiness.ManualSms,
                    Name = telNumber.Value,
                };
                try
                {
                    await _pushDomainService.PushMsgAsync(inDto, HttpContext.RequestAborted);
                }
                catch (Exception e)
                {
                    errorSB.Append(e.Message);
                    errorCount++;
                    continue;
                }
                count++;
            }
            return $"成功发送: {count}, 失败: {errorCount}. " + (errorCount != 0 ? "" : errorSB.ToString());
        }

        /// <summary>
        /// 手动发送短信页面基础数据
        /// </summary>
        /// <returns></returns>
        [HttpGet("send/basedata")]
        public async Task<dynamic> SendMessageBaseDataAsync()
        {
            var users = await _userRepository.Queryable()
                .Select(m => new { m.Id, m.PhoneNo, m.Name }).ToListAsync();
            return new Dictionary<string, dynamic>() { { "contacts", users } };
        }

        #endregion

        #region 查询短信

        /// <summary>
        /// 查询短信
        /// </summary>
        /// <param name="pagedDto"></param>
        /// <returns></returns>
        [HttpGet("getlist")]
        public async Task<PagedDto<MessageDataDto>> AllMessage([FromQuery] MessagePagedDto pagedDto)
        {
            var (total, items) = await _messageRepository
                .Queryable()
                .Includes(it => it.Order)
                .WhereIF(pagedDto.PushBusiness.HasValue, d => d.PushBusiness == pagedDto.PushBusiness)
                .WhereIF(pagedDto.Status.HasValue, d => d.SendState == pagedDto.Status)
                .WhereIF(!string.IsNullOrEmpty(pagedDto.Keyword),
                    d => d.Name.Contains(pagedDto.Keyword!) || d.Content.Contains(pagedDto.Keyword!) ||
                         d.TelNumber.Contains(pagedDto.Keyword!) || d.CreatorName.Contains(pagedDto.Keyword!) ||
                         d.CreatorOrgName.Contains(pagedDto.Keyword!))
                .WhereIF(pagedDto.StartTime.HasValue, d => d.SendTime >= pagedDto.StartTime)//发送时间开始
                .WhereIF(pagedDto.EndTime.HasValue, d => d.SendTime <= pagedDto.EndTime)//发送时间结束
                 .WhereIF(pagedDto.CreationStartTime.HasValue, d => d.CreationTime >= pagedDto.CreationStartTime)//添加时间开始
                .WhereIF(pagedDto.CreationEndTime.HasValue, d => d.CreationTime <= pagedDto.CreationEndTime)//添加时间结束
                .WhereIF(!string.IsNullOrEmpty(pagedDto.UserName), d => d.Name.Contains(pagedDto.UserName))
                 .WhereIF(!string.IsNullOrEmpty(pagedDto.TelNumber), d => d.TelNumber.Contains(pagedDto.TelNumber))
                .WhereIF(!string.IsNullOrEmpty(pagedDto.SendName), d => d.CreatorName.Contains(pagedDto.SendName))
                .WhereIF(!string.IsNullOrEmpty(pagedDto.SendOrg), d => d.CreatorOrgName.Contains(pagedDto.SendOrg))
                .WhereIF(!string.IsNullOrEmpty(pagedDto.SendContent), d => d.Content.Contains(pagedDto.SendContent))
                .WhereIF(pagedDto.IsSmsReply.HasValue && pagedDto.IsSmsReply == false, d => d.IsSmsReply == false)
                .WhereIF(pagedDto.IsSmsReply.HasValue && pagedDto.IsSmsReply == true, d => d.IsSmsReply == true)
                .OrderByDescending(it => it.CreationTime)
                .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize, HttpContext.RequestAborted);

            return new PagedDto<MessageDataDto>(total, _mapper.Map<IReadOnlyList<MessageDataDto>>(items));
        }

        /// <summary>
        /// 列表页面基础数据
        /// </summary>
        /// <returns></returns>
        [HttpGet("list-data")]
        public async Task<object> ListData()
        {
            var rsp = new
            {
                EPushBusinessData = EnumExts.GetDescriptions<EPushBusiness>(),
                ESendStateData = EnumExts.GetDescriptions<ESendState>()
            };
            return rsp;
        }

        #endregion


        #region 批量短信任务

        /// <summary>
        /// 新增批量短信任务
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("add-batchsmstask")]
        public async Task AddBatchSmsTask([FromBody] AddBatchSmsTaskDto dto)
        {
            //验证是否有重复电话
            if (dto.BatchSmsTaskDetail.DistinctBy(x => x.PhoneNum).Count() != dto.BatchSmsTaskDetail.Count)
            {
                throw UserFriendlyException.SameMessage("任务中存在重复外呼号码，请检查后重新提交");
            }
            var task = _mapper.Map<BatchSmsTask>(dto);
            task.SmsCount = dto.BatchSmsTaskDetail.Count;
            task.SmsTaskState = ESmsTaskState.WaitDo;
            await _batchSmsTaskRepository.AddAsync(task, HttpContext.RequestAborted);

            var detail = _mapper.Map<List<BatchSmsTaskDetail>>(dto.BatchSmsTaskDetail);
            detail.ForEach(x =>
            {
                x.TaskId = task.Id;
            });
            await _batchSmsTaskDetailRepository.AddRangeAsync(detail, HttpContext.RequestAborted);
            //推送任务延迟消息
            //_capPublisher.PublishDelay(expiredTimeConfig.NearlyExpiredTime - DateTime.Now, EventNames.HotlineOrderNearlyExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
            _capPublisher.PublishDelay(task.PlanSendTime - DateTime.Now, EventNames.HotlineBatchSmsTask, new PublishBatchSmsTaskDto() { TaskId = task.Id });
        }

        /// <summary>
        /// 终止任务
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("stop-batchsmstask")]
        public async Task StopBatchSmsTask([FromQuery] string id)
        {
            var task = await _batchSmsTaskRepository.GetAsync(id, HttpContext.RequestAborted);
            if (task == null)
            {
                throw UserFriendlyException.SameMessage("无效任务");
            }

            if (task.SmsTaskState != ESmsTaskState.WaitDo)
            {
                throw UserFriendlyException.SameMessage("当前任务状态不能终止");
            }

            task.SmsTaskState = ESmsTaskState.Stop;
            await _batchSmsTaskRepository.UpdateAsync(task);
        }

        /// <summary>
        /// 短信任务列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("batchsmstask-query")]
        public async Task<PagedDto<BatchSmsTaskRep>> BatchSmsTaskList([FromQuery] BatchSmsTaskReq dto)
        {
            var (total, items) = await _batchSmsTaskRepository.Queryable()
                .WhereIF(string.IsNullOrEmpty(dto.TaskName) == false, x => x.TaskName.Contains(dto.TaskName))
                .WhereIF(dto.State.HasValue, x => x.SmsTaskState == dto.State)
                .WhereIF(dto.StateTime.HasValue, x => x.CreationTime >= dto.StateTime)
                .WhereIF(dto.EndTime.HasValue, x => x.CreationTime < dto.EndTime)
                .OrderByDescending(x => x.CreationTime)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

            return new PagedDto<BatchSmsTaskRep>(total, _mapper.Map<IReadOnlyList<BatchSmsTaskRep>>(items));
        }
        /// <summary>
        /// 短信任务基础数据
        /// </summary>
        /// <returns></returns>
        [HttpGet("batchsmstask-basedata")]
        public async Task<object> BatchSmsTaskBaseData()
        {
            return new
            {
                SmsTaskState = EnumExts.GetDescriptions<ESmsTaskState>()
            };
        }

        /// <summary>
        /// 获取批量短信任务详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("batchsmstask-entity")]
        public async Task<BatchSmsTaskRep> BatchSmsTaskEntity([FromQuery] string id)
        {
            var model = await _batchSmsTaskRepository.GetAsync(id, HttpContext.RequestAborted);
            if (model == null)
            {
                throw UserFriendlyException.SameMessage("无效任务");
            }
            return _mapper.Map<BatchSmsTaskRep>(model);
        }

        /// <summary>
        /// 获取批量短信任务明细
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpGet("batchsmsmtaskdetail-query")]
        public async Task<PagedDto<AddBatchSmsTaskDetailDto>> BatchSmsTaskDetailList([FromQuery] BatchSmsTaskDetailListReq dto)
        {
            var (total, items) = await _batchSmsTaskDetailRepository.Queryable()
                .Where(x => x.TaskId == dto.Id)
                .WhereIF(string.IsNullOrEmpty(dto.Name) == false, x => x.Name.Contains(dto.Name))
                .WhereIF(string.IsNullOrEmpty(dto.PhoneNum) == false, x => x.PhoneNum.Contains(dto.PhoneNum))
                .OrderByDescending(x => x.CreationTime)
                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);

            return new PagedDto<AddBatchSmsTaskDetailDto>(total, _mapper.Map<IReadOnlyList<AddBatchSmsTaskDetailDto>>(items));
        }


        #endregion
    }
}