using Hotline.Article;
using Hotline.Caching.Interfaces;
using Hotline.Caching.Services;
using Hotline.Realtimes;
using Hotline.Share.Dtos.Realtime;
using Hotline.Users;
using Microsoft.AspNetCore.SignalR;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;
using XF.Domain.Repository;

namespace Hotline.Api.Realtimes;

public class RealtimeService : IRealtimeService, IScopeDependency
{
    private readonly IHubContext<HotlineHub> _hubContext;
    private readonly IRealtimeCacheManager _realtimeCacheManager;
    private readonly IRepository<CircularRecord> _circularRecordRepository;
    private readonly IRepository<User> _userRepository;

    public RealtimeService(
        IHubContext<HotlineHub> hubContext,
        IRealtimeCacheManager realtimeCacheManager,
        IRepository<CircularRecord> circularRecordRepository,
        IRepository<User> userRepository)
    {
        _hubContext = hubContext;
        _realtimeCacheManager = realtimeCacheManager;
        _circularRecordRepository = circularRecordRepository;
        _userRepository = userRepository;
    }

    #region 通讯通知

    /// <summary>
    /// 回铃事件通知
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="dto"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    /// <exception cref="UserFriendlyException"></exception>
    public Task AlertAsync(string userId, AlertDto dto, CancellationToken cancellationToken) =>
        SendCallCenterMsgAsync(userId, RealtimeMethods.Alert, dto, cancellationToken);


    /// <summary>
    /// 振铃事件通知
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="dto"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    /// <exception cref="UserFriendlyException"></exception>
    public Task RingAsync(string userId, RingDto dto, CancellationToken cancellationToken) =>
        SendCallCenterMsgAsync(userId, RealtimeMethods.Ring, dto, cancellationToken);

    /// <summary>
    /// 应答事件通知
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="dto"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public Task AnsweredAsync(string userId, AnsweredDto dto, CancellationToken cancellationToken) =>
        SendCallCenterMsgAsync(userId, RealtimeMethods.Answered, dto, cancellationToken);


    /// <summary>
    /// 电话挂断事件通知
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="dto"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public Task ByeAsync(string userId, ByeDto dto, CancellationToken cancellationToken) =>
        SendCallCenterMsgAsync(userId, RealtimeMethods.Bye, dto, cancellationToken);

    /// <summary>
    /// 小休审核通过后通知前端
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    /// <exception cref="UserFriendlyException"></exception>
    public Task RestApplyPassAsync(string userId, CancellationToken cancellationToken) =>
        SendCallCenterMsgAsync(userId, RealtimeMethods.RestApplyPass, null, cancellationToken);


    /// <summary>
    /// 通话队列通知
    /// </summary>
    /// <param name="list"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task CallQueueAsync(List<CallCacheManager.CallDtoRedis> list, CancellationToken cancellationToken)
    {
        await _hubContext.Clients.Group(RealtimeGroupNames.CallCenter)
            .SendAsync(RealtimeMethods.CallQueue, list, cancellationToken);

        //var works = _userCacheManager.GetWorks();
        //if (works != null)
        //{
        //    var sendList = works.Where(x => !string.IsNullOrEmpty(x.SignalRId)).Select(x => x.SignalRId).ToList();
        //    foreach (var work in sendList)
        //    {
        //        await _hubContext.Clients.Client(work).SendAsync(RealtimeMethods.CallQueue, list, cancellationToken);
        //    }
        //}
    }

    /// <summary>
    /// 话机空闲通知
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    /// <exception cref="UserFriendlyException"></exception>
    public Task IdleAsync(string userId, CancellationToken cancellationToken) =>
        SendCallCenterMsgAsync(userId, RealtimeMethods.Idle, new { EventName = "Idle" }, cancellationToken);

    #endregion

    #region 系统信息通知

    /// <summary>
    /// 新消息通知
    /// </summary>
    /// <param name="id"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task CircularRecoordAsync(string id, string title, string sendContent, CancellationToken cancellationToken)
    {
        //获取所有需要推送的
        var record = await _circularRecordRepository.Queryable().Where(x => x.Id == id).FirstAsync();

        if (record.CircularType == Share.Enums.Article.ECircularType.Person)
        {
            //个人数量
            await SendToUserAsync(record.UserId, RealtimeMethods.CircularRecord,
                new CircularRecoordDto() { CircularType = Share.Enums.Article.ECircularType.Person, Count = record.RecordCount, SendContent = sendContent, Title = title },
                cancellationToken);
        }
        else
        {
            //部门
            var orguserList = await _userRepository.Queryable().Where(x => x.OrgId == record.OrgId).ToListAsync();
            foreach (var user in orguserList)
            {
                try
                {
                    //数量
                    await SendToUserAsync(user.Id, RealtimeMethods.CircularRecord,
                        new CircularRecoordDto()
                        { CircularType = Share.Enums.Article.ECircularType.Org, Count = record.RecordCount, SendContent = sendContent, Title = title },
                        cancellationToken);

                }
                catch
                {
                }
            }
        }
    }

    #endregion

    #region 大屏.数据展示

    public Task BsDataShowChanged1Async(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea1, obj, cancellationToken);
    public Task BsDataShowChanged2Async(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea2, obj, cancellationToken);
    public Task BsDataShowChanged3Async(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea3, obj, cancellationToken);
    public Task BsDataShowChanged4Async(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea4, obj, cancellationToken);
    public Task BsDataShowChanged5Async(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea5, obj, cancellationToken);
    public Task BsDataShowChanged6Async(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea6, obj, cancellationToken);
    public Task BsDataShowChanged7Async(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea7, obj, cancellationToken);
    public Task BsDataShowChanged8Async(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea8, obj, cancellationToken);

    #endregion

    #region 大屏坐席数据
    public Task BsSeatStateDataShowChangedAsync1(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigScreenSeatState, RealtimeMethods.BsSeatStateDataShowArea1, obj, cancellationToken);

    public Task BsSeatStateDataShowChangedAsync2(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigScreenSeatState, RealtimeMethods.BsSeatStateDataShowArea2, obj, cancellationToken);

    public Task BsSeatStateDataShowChangedAsync3(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigScreenSeatState, RealtimeMethods.BsSeatStateDataShowArea3, obj, cancellationToken);

    public Task BsSeatStateDataShowChangedAsync4(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigScreenSeatState, RealtimeMethods.BsSeatStateDataShowArea4, obj, cancellationToken);
    #endregion

    #region 数据大屏

    /// <summary>
    /// 推送年月日工单量数据
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public Task OrderCountStatisticsAsync(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigDataScreen, RealtimeMethods.OrderCountStatistics, obj, cancellationToken);

    /// <summary>
    /// 推送办理中工单概览
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public Task OrderHandlingDetailAsync(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigDataScreen, RealtimeMethods.OrderHandlingDetail, obj, cancellationToken);

    /// <summary>
    /// 推送二次办理中工单概览
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public Task OrderSecondaryHandlingDetailAsync(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigDataScreen, RealtimeMethods.OrderSecondaryHandlingDetail, obj, cancellationToken);

    /// <summary>
    /// 推送110来源工单
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public Task OrderSourePoliceDetailAsync(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.BigDataScreen, RealtimeMethods.OrderSourePoliceDetail, obj, cancellationToken);
    #endregion

    /// <summary>
    /// 司法大屏--工单明细
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public Task EnforcementOrderHandlingDetailAsync(object obj, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.EnforcementBigDataScreen, RealtimeMethods.EnforcementOrderHandlingDetail, obj, cancellationToken);


    #region 话务排队信息

    public Task TodayWaitNumAsync(int count, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.CallCenter, RealtimeMethods.ToDayWaitNum, count, cancellationToken);

    public Task CurrentWaitNumAsync(int count, CancellationToken cancellationToken) =>
        SendToGroupAsync(RealtimeGroupNames.CallCenter, RealtimeMethods.CurrentWaitNum, count, cancellationToken);


    #endregion
    #region private

    private async Task SendCallCenterMsgAsync(string userId, string msg, object? value, CancellationToken cancellationToken)
    {
        var connection = await _realtimeCacheManager.GetConnectionAsync(userId, cancellationToken);
        CheckIfInGroup(connection, RealtimeGroupNames.CallCenter);
        await _hubContext.Clients.Client(connection.ConnectionId).SendAsync(msg, value, cancellationToken);
    }

    private async Task CheckIfInCallCenter(string userId, CancellationToken cancellationToken)
    {
        var isIn = await _realtimeCacheManager.IsInGroupAsync(userId, RealtimeGroupNames.CallCenter, cancellationToken);
        if (!isIn)
            throw UserFriendlyException.SameMessage("该用户不属于分组：呼叫中心");
    }

    private void CheckIfInGroup(RealtimeConnection connection, string groupName)
    {
        if (!connection.IsInGroup(groupName))
            throw UserFriendlyException.SameMessage($"该用户不属于分组：{groupName}");
    }

    private async Task SendToUserAsync(string userId, string msg, object? value, CancellationToken cancellationToken)
    {
        var connection = await _realtimeCacheManager.GetConnectionAsync(userId, cancellationToken);
        await _hubContext.Clients.Client(connection.ConnectionId).SendAsync(msg, value, cancellationToken);
    }

    private Task SendToGroupAsync(string groupName, string method, object? value, CancellationToken cancellationToken) =>
        _hubContext.Clients.Group(groupName).SendAsync(method, value, cancellationToken);

    #endregion



}