using CloudGaming.Code.Contract;
using CloudGaming.Code.DataAccess;
using CloudGaming.Code.JY;
using CloudGaming.Code.Monitor;
using CloudGaming.DtoModel.PlayGame;

using HuanMeng.DotNetCore.Processors;

using Refit;

using StackExchange.Redis;


namespace CloudGaming.Code.Game;
/// <summary>
/// 游戏服务
/// </summary>
public class PlayGameProcessor(IServiceProvider serviceProvider) : ThreadProcessor
{
    protected override async void Proc_Do()
    {
        var appConfigs = AppConfigurationExtend.AppConfigs.Where(it => it.Key != "default")
            .Select(it => it.Value)
            .ToList();
        
        // 为每个项目启动一个独立的任务
        foreach (var appConfig in appConfigs)
        {
            _ = Task.Run(() => ProcessAppConfigLoop(appConfig));
        }

        // 主线程可以继续执行其他逻辑或保持服务运行
    }

    /// <summary>
    /// 单个项目的处理循环
    /// </summary>
    private async Task ProcessAppConfigLoop(AppConfig appConfig)
    {
        while (_isRunning)
        {
            try
            {
                // 执行项目的查询和处理逻辑
                await ProcessAppConfig(appConfig).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                // 记录日志或处理异常
                Console.WriteLine($"处理项目 {appConfig.DomainName} 时发生异常: {ex.Message}");
            }

            // 暂停5秒
            await Task.Delay(5000).ConfigureAwait(false);
        }
    }

    /// <summary>
    /// 单次处理项目逻辑
    /// </summary>
    private async Task ProcessAppConfig(AppConfig appConfig)
    {
        var userNotActionDisconnect = DateTime.Now.AddSeconds(-appConfig.GameConfig.UserNotActionDisconnect);
        var userNotActionEndGame = DateTime.Now.AddSeconds(-appConfig.GameConfig.UserNotActionEndGame);
        //30 秒检测不到排队信息，则判断排队掉线
        var userNotQueue = DateTime.Now.AddSeconds(-30);
        //60 秒检查不到排队，则判断排队结束
        var userNotQueueEnd = DateTime.Now.AddSeconds(-60);
        using var scope = serviceProvider.CreateScope();
        var app = scope.ServiceProvider.GetRequiredService<AppConfig>();
        appConfig.ToAppConfig(app);
        var dao = scope.ServiceProvider.GetDAO(appConfig);
        var redis = appConfig.GetRedisDataBase();
        var redisServer = appConfig.GetRedisServer();

        var keyPattern = $"{PlayGameExtend.GetPlayGameKeyPrefix}:*";
        var keys = await redisServer.ScanKeysAsync(keyPattern, 20000).ConfigureAwait(false);

        var tasks = keys.Select(async gameKey =>
        {
            var gameInfo = await redis.StringGetAsync<PlayGameUserInfo>(gameKey).ConfigureAwait(false);
            return gameInfo;
        });

        var gameInfoList = (await Task.WhenAll(tasks).ConfigureAwait(false)).Where(x => x != null).ToList();

        // 处理未操作断线的玩家
        var userPlayGameNotActionEndGame = gameInfoList
            .Where(it => it.GameStatus == PlayGameStatus.游戏掉线 && it.PlayGameHeartbeatAt < userNotActionEndGame)
            .ToList();
        if (userPlayGameNotActionEndGame.Count > 0)
            foreach (var user in userPlayGameNotActionEndGame)
            {
                await EndGameAsync(user, appConfig, dao, redis).ConfigureAwait(false);
                gameInfoList.Remove(user);
            }

        // 处理未操作标记为掉线的玩家
        var userPlayGameNotAction = gameInfoList
            .Where(it => (it.GameStatus == PlayGameStatus.游戏中 || it.GameStatus == PlayGameStatus.开始游戏) && it.PlayGameHeartbeatAt < userNotActionDisconnect)
            .ToList();
        if (userPlayGameNotAction.Count > 0)
            foreach (var user in userPlayGameNotAction)
            {
                user.PlayGameUserNotAction();
                await user.SaveChangesAsync(dao, redis).ConfigureAwait(false);
            }

        //用户排队掉线人
        var userPlayGameNotQueueEndGame = gameInfoList
    .Where(it => it.GameStatus == PlayGameStatus.排队掉线 && it.LastPlayQueueAt < userNotQueueEnd)
    .ToList();
        if (userPlayGameNotQueueEndGame.Count > 0)
            foreach (var user in userPlayGameNotQueueEndGame)
            {
                await EndGameQueueAsync(user, appConfig, dao, redis).ConfigureAwait(false);
                gameInfoList.Remove(user);
            }

        var userPlayGameNotQueue = gameInfoList
            .Where(it => it.GameStatus == PlayGameStatus.排队中 && it.LastPlayQueueAt < userNotQueue)
            .ToList();
        if (userPlayGameNotQueue.Count > 0)
            foreach (var user in userPlayGameNotQueue)
            {
                user.PlayGameUserNotQueue();
                await user.SaveChangesAsync(dao, redis).ConfigureAwait(false);
            }
        if (!MonitorExtend.AppMonitorConfigs.TryGetValue(app.Identifier, out var appMonitorInfo))
        {
            appMonitorInfo = new DtoModel.Other.AppMonitorInfo() { };
            MonitorExtend.AppMonitorConfigs.TryAdd(app.Identifier, appMonitorInfo);
        }
        //替换引用
        appMonitorInfo.PlayGameUserInfos = gameInfoList;
        
        //状态统计
        //var gameStatusStatistics = gameInfoList.GroupBy(it => it.GameStatus).ToDictionary(it => it.Key, it => it.Count());//  .Select(it => new { GameStatus = it.Key, GameCount = it.Count() }).ToList();
    }

    /// <summary>
    /// 结束游戏逻辑
    /// </summary>
    private async Task EndGameAsync(PlayGameUserInfo user, AppConfig appConfig, DAO dao, IDatabase redis)
    {
        HttpClient httpClient = new HttpClient(new JYApiAppConfigHandler(appConfig, user.Ip));
        httpClient.BaseAddress = new Uri(appConfig.GameConfig.BsUrl);
        var jyApi = RestService.For<IJYApi>(httpClient);

        var playGameCommonSetting = new PlayGameCommonSetting
        {
            ScId = user.ScId,
            Sn = user.Sn
        };

        var jyResponse = await jyApi.StopGame(playGameCommonSetting).ConfigureAwait(false);

        user.PlayGameDiaoXian(jyResponse);
        await user.SaveChangesAsync(dao, redis).ConfigureAwait(false);
    }

    /// <summary>
    /// 排队掉线结束游戏逻辑
    /// </summary>
    private async Task EndGameQueueAsync(PlayGameUserInfo user, AppConfig appConfig, DAO dao, IDatabase redis)
    {
        HttpClient httpClient = new HttpClient(new JYApiAppConfigHandler(appConfig, user.Ip));
        httpClient.BaseAddress = new Uri(appConfig.GameConfig.BsUrl);
        var jyApi = RestService.For<IJYApi>(httpClient);

        var playGameCommonSetting = new PlayGameQueue(user.Sn, user.UserId)
        {
            PlayQueueId = user.ScId,
            Sn = user.Sn
        };

        var jyResponse = await jyApi.CancelQueue(playGameCommonSetting).ConfigureAwait(false);
        user.PlayGameUserNotQueueEnd(jyResponse);
        await user.SaveChangesAsync(dao, redis).ConfigureAwait(false);
    }
}
