using System.Threading.Tasks;
using System;
using Wicture.DbRESTFul.Infrastructure.Repository;
using System.Linq;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Data;
using Wicture.DbRESTFul.Cache;
using System.Security.Cryptography.X509Certificates;
using Newtonsoft.Json;
using System.Runtime.Intrinsics.X86;
using JiaZhiQuan.Common.Models.VO;
using JiaZhiQuan.Common.Models.PO;

namespace JiaZhiQuan.Common
{
    public static partial class RepositoryExtension
    {

        public class ActivityCzdTaskRecord
        {
            public int id { get; set; }
            public long userId { get; set; }
            public int betPoints { get; set; }
            public int betType { get; set; }
            public DateTime createAt { get; set; }
            public int gainPoints { get; set; }
            public int gameResult { get; set; }
        }

        public class ActivityCzdMockModel
        {
            public int fallUsers { get; set; }
            public int riseUsers { get; set; }
            public int points { get; set; }
            public DateTime execTime { get; set; }
        }


        public static async Task<List<int>> GetCzdPointListByContract(this DbRESTFulRepository repository, RedisCacheProvider cacheProvider, int contractId)
        {
            var key = CacheKeys.ActivityCzdPointList(contractId);
            var list = await cacheProvider.Get<List<int>>(key);
            if (list == null)
            {
                list = (await repository.QuerySingleOrDefaultAsync<string>($"select pointsList from n_activity_czd_contract where id={contractId}") ?? string.Empty)
                .Split(',', StringSplitOptions.RemoveEmptyEntries)
                .Select(e => int.Parse(e)).ToList();
                await cacheProvider.Set(key, list, CacheKeys.ActivityCzdPointListCacheSecs);
            }
            return list;
        }


        /// <summary>
        /// 获取随机人数和随机价值币
        /// </summary>
        /// <param name="minCount">包含</param>
        /// <param name="maxCount">包含</param>
        /// <param name="mode">0 双方都加同样的，2 仅跌的，1 仅涨的</param>
        public static async Task<bool> GenerateActivityCzdMockData(this DbRESTFulRepository repository, RedisCacheProvider cacheProvider, int contractId, int taskId, int minCount, int maxCount, int minutes, int mode = 0)
        {
            var pointsArr = await repository.GetCzdPointListByContract(cacheProvider, contractId);
            if (pointsArr.Count == 0) return false;
            var rand = new Random();
            var count = rand.Next(minCount, maxCount + 1);
            if (count == 0) return true;

            var list = new List<ActivityCzdMockModel>();
            var maxBatch = Math.Min(count, 10);
            for (var i = 0; i < count; i++)
            {
                var time = DateTime.Now.AddMinutes(rand.NextDouble() * minutes);
                var batch = rand.Next(1, maxBatch + 1);
                var model = new ActivityCzdMockModel { execTime = time };
                if (mode == 2 || mode == 0)
                {
                    model.fallUsers = batch;
                }
                if (mode == 1 || mode == 0)
                {
                    model.riseUsers = batch;
                }
                for (var j = 0; j < batch; j++)
                {
                    model.points += pointsArr[rand.Next(Math.Min(3, pointsArr.Count))];
                }
                if (mode == 0)
                {
                    model.points *= 2;
                }
                list.Add(model);
                i += batch - 1;
            }
            await repository.QueryAsync<dynamic>($"insert into n_activity_czd_mock_action (taskId, fallUsers, riseUsers, points, execTime, createAt) values ({taskId}, @fallUsers, @riseUsers, @points, @execTime, now())", list, null, null, false);
            return true;
        }

        /// <summary>
        /// 结束某一个任务
        /// </summary>
        /// <param name="contractId">合约组编号</param>
        /// <param name="date">yyyy-MM-dd</param>
        /// <param name="contractResult">1 涨 2 跌 3 平</param>
        public static async Task<bool> EndActivityCzdTask(this DbRESTFulRepository repository, int contractId, string date, int contractResult)
        {
            var task = await repository.QuerySingleOrDefaultAsync<dynamic>($"select t.id, t.activityId, t.contractId, c.contractName, t.date from n_activity_czd_task as t left join n_activity_czd_contract as c on t.contractId=c.id where t.contractId={contractId} and t.date='{date}' and t.contractResult=0");
            if (task == null) return false;

            // 判断是否是最新的已结束的任务
            var isNewTask = (await repository.QuerySingleOrDefaultAsync<int>(
                $"select id from n_activity_czd_task where id>{task.id} and contractResult>0 limit 1")) == 0;

            var activityId = task.activityId;
            var activityName =
                await repository.QuerySingleOrDefaultAsync<string>(
                    $"select title from n_activity where id={activityId}");
            var pointChangeDescription = $"活动奖励-{activityName}";

            var allRecords = (await repository.QueryAsync<ActivityCzdTaskRecord>($"select id, userId, betType, betPoints, createAt from n_activity_czd_task_records where taskId={task.id}")).ToList();
            var risePoints = 0;
            var fallPoints = 0;
            foreach (var record in allRecords)
            {
                // 跌
                if (record.betType == 2)
                {
                    fallPoints += record.betPoints;
                }
                // 涨
                else
                {
                    risePoints += record.betPoints;
                }
            }

            var platformTotalPoints = 0; // 平台所出价值币
            var totalWinPoints = 0; // 赢方总获取的价值币（不记成本）
            int totalPoints = contractResult == 2 ? risePoints : fallPoints; // 瓜分总价值币
            int totalWinBetPoints = contractResult == 2 ? fallPoints : risePoints; // 赢方总投注价值币
            var rate = totalWinBetPoints > 0 ? (double)totalPoints / totalWinBetPoints : 0;
            var winUserIds = new List<long>();
            foreach (var record in allRecords)
            {
                var win = (record.betType == 2 && contractResult == 2) || (record.betType != 2 && contractResult != 2);
                record.gameResult = win ? 1 : 2;
                if (win)
                {
                    var p = (int)Math.Floor(rate * record.betPoints);
                    if (p < 20) p = 20;
                    totalWinPoints += p;
                    record.gainPoints = record.betPoints + p;
                    winUserIds.Add(record.userId);
                }
                else
                {
                    record.gainPoints = 0;
                }
            }

            platformTotalPoints = totalWinPoints - totalPoints;

            var updateRecords = allRecords.Select(e =>
            {
                return new
                {
                    e.id,
                    e.gainPoints,
                    e.gameResult,
                };
            }).ToList();
            var updateStats = allRecords.Select(e =>
            {
                return new
                {
                    e.userId,
                    e.createAt,
                    win = e.gameResult == 1 ? 1 : 0,
                    points = e.gainPoints - e.betPoints,
                };
            }).ToList();
            var pointsRecords = allRecords.Where(e => e.gainPoints > 0).Select(e =>
            {
                return new
                {
                    e.userId,
                    points = e.gainPoints,
                };
            }).ToList();

            var execCount = 0;
            var taskEndTime = ((DateTime)task.date).ToString("yyyy-MM-dd 15:00:00");

            using var conn = repository.ConnectionManager.GetConnection(false);
            conn.Open();
            var trans = conn.BeginTransaction();
            try
            {
                execCount = await repository.QuerySingleOrDefaultAsync<int>($"update n_activity_czd_task set contractResult={contractResult}, extraPoints={platformTotalPoints} where id={task.id} and contractResult=0; select row_count() as count;", null, conn, trans);
                if (execCount > 0)
                {
                    await repository.QueryAsync<dynamic>("update n_activity_czd_task_records set gainPoints=@gainPoints, remind=1, gameResult=@gameResult where id=@id and gameResult=0;", updateRecords, conn, trans);
                    if (isNewTask)
                    {
                        await repository.QueryAsync<dynamic>(@$"update n_activity_czd_task_statistic set
winTimes=winTimes+@win, continuousTimes=(case @win when 1 then continuousTimes+1 else 0 end),
totalEarnPoints=totalEarnPoints+@points, lastJoinAt=(case @createAt<lastJoinAt when 1 then lastJoinAt else @createAt end),
latestWinAt=(case @win when 1 then (case latestWinAt<'{taskEndTime}' when 1 then '{taskEndTime}' else latestWinAt end) else latestWinAt end) where contractId={contractId} and userId=@userId", updateStats, conn, trans);
                        // 如果将其他未参与用户的连中次数设置成-1
                        await repository.QueryAsync<dynamic>($"update n_activity_czd_task_statistic set continuousTimes=0 where contractId={contractId} [and userId not in @userIds]", new { userIds = winUserIds.Count > 0 ? winUserIds : null }, conn, trans);
                    }
                    else
                    {
                        await repository.QueryAsync<dynamic>(@$"update n_activity_czd_task_statistic set
winTimes=winTimes+@win,
totalEarnPoints=totalEarnPoints+@points, lastJoinAt=(case @createAt<lastJoinAt when 1 then lastJoinAt else @createAt end),
latestWinAt=(case @win when 1 then (case latestWinAt<'{taskEndTime}' when 1 then '{taskEndTime}' else latestWinAt end) else latestWinAt end) where contractId={contractId} and userId=@userId", updateStats, conn, trans);
                    }
                    // 给用户添加价值币
                    if (pointsRecords.Count > 0)
                    {
                        await repository.QueryAsync<dynamic>($"insert into n_user_points_record(userId, points, `way`, extra, description, createAt, createAtDate) values(@userId, @points, 'ACTIVITY', '{activityId}', '{pointChangeDescription}', now(), now())", pointsRecords, conn, trans);
                        await repository.QueryAsync<dynamic>($"update n_user_statistic set points=points+@points where userId=@userId", pointsRecords, conn, trans);
                    }
                }
                trans.Commit();
            }
            catch (Exception ex)
            {
                trans.Rollback();
                throw ex;
            }

            if (execCount > 0 && !isNewTask)
            {
                // 更新用户的连中次数，最多50次
                var taskIds = (await repository.QueryAsync<int>(
                    $"select id from n_activity_czd_task where contractId={contractId} and contractResult>0 order by id desc limit 50",
                    null, conn)).ToList();
                // 查询出所有参与记录
                var records =
                    (await repository.QueryAsync<dynamic>(
                        $"select taskId, userId from n_activity_czd_task_records where taskId in @taskIds and gameResult=1",
                        new { taskIds })).ToList();
                // 按人进行统计
                var userIdCountMap = new Dictionary<long, int>();
                var completedUserIds = new HashSet<long>();
                var first = true;
                foreach (var taskId in taskIds)
                {
                    var uids = records.Where(e => e.taskId == taskId).Select(e => (long)e.userId).ToHashSet();
                    if (first)
                    {
                        records.ForEach(e =>
                        {
                            if (!userIdCountMap.ContainsKey(e.userId))
                            {
                                userIdCountMap.Add(e.userId, uids.Contains(e.userId) ? 1 : 0);
                            }
                        });
                        first = false;
                    }
                    else
                    {
                        userIdCountMap.Keys.ForEach(uid =>
                        {
                            if (completedUserIds.Contains(uid)) return;
                            if (uids.Contains(uid) && userIdCountMap.ContainsKey(uid) && userIdCountMap[uid] != 0) userIdCountMap[uid]++;
                            else completedUserIds.Add(uid);
                        });
                    }
                }
                // 更新记录
                if (userIdCountMap.Count > 0)
                {
                    var query = userIdCountMap.Select(e => new { userId = e.Key, count = e.Value }).ToList();
                    await repository.QueryAsync<dynamic>(
                        $"update n_activity_czd_task_statistic set continuousTimes=@count where contractId={contractId} and userId=@userId",
                        query, conn, null, false);
                }
            }
            return execCount > 0;
        }

        /// <summary>
        /// 根据给定变更的奖励任务编号列表来更新活动的报名状态
        /// </summary>
        private static async Task UpdateActivitySignupState(this DbRESTFulRepository repository,
            List<int> rewardIds, IDbConnection conn)
        {
            var rewards = (await repository.QueryAsync<dynamic>(
                "select id, activityId, name, requirement, signupLimit from n_activity_reward where id in @ids and signupLimit>0", new
                {
                    ids = rewardIds
                }, conn)).ToList();
            if (rewards.Count == 0) return;
            var allActivityIds = rewards.Select(e => (int)e.activityId).Distinct().ToList();
            rewardIds = rewards.Select(e => (int)e.id).ToList();
            var completeStat = (await repository.QueryAsync<dynamic>(
                @"select rewardId, count(1) as count from n_activity_reward_user_state
                        where rewardId in @rewardIds and state in(0, 1) group by rewardId",
                new { rewardIds }, conn)).ToList();
            if (completeStat.Count == 0) return;
            var cannotSignupActivityIds = new HashSet<int>();
            var updateRecords = new List<dynamic>();
            rewards.ForEach(p =>
            {
                if (cannotSignupActivityIds.Contains(p.activityId)) return;
                var existStat = completeStat.FirstOrDefault(e => e.rewardId == p.id);
                if (existStat == null) return;
                if (existStat.count >= p.signupLimit)
                {
                    cannotSignupActivityIds.Add(p.activityId);
                    updateRecords.Add(new
                    {
                        p.name,
                        p.activityId,
                        p.requirement,
                        existStat.count,
                        p.signupLimit
                    });
                }
            });
            var canSignupActivityIds = allActivityIds.Where(i => !cannotSignupActivityIds.Contains(i)).ToList();
            var activityInfos = (await repository.QueryAsync<dynamic>("select id, signupState, signupCount, signupStartAt, signupEndAt from n_activity where id in @ids", new
            {
                ids = allActivityIds
            }, conn)).ToList();
            // 过滤掉当前不可报名的活动编号，不可报名的无需更新
            var validCannotSignupActivityIds = cannotSignupActivityIds
                .Where(i => !activityInfos.Any(a => a.id == i && a.signupState == 1)).ToList();
            if (validCannotSignupActivityIds.Count > 0)
            {
                await repository.QueryAsync<dynamic>(
                    $"update n_activity set signupState=1 where id in @ids", new
                    {
                        ids = validCannotSignupActivityIds
                    }, conn, null, false);
                await repository.QueryAsync<dynamic>($"insert into n_activity_signup_state_change(activityId, `event`, createAt) values (@activityId, @eventTxt, now())", validCannotSignupActivityIds.Select(
                    i =>
                    {
                        var r = updateRecords.First(r => r.activityId == i);
                        var name = string.IsNullOrEmpty(r.name)
                            ? $"邀请{r.requirement}人"
                            : r.name;
                        return new
                        {
                            activityId = i,
                            eventTxt = $"停止报名（原因：任务\"{name}\"完成人数{r.count}达到上限）"
                        };
                    }));
            }

            if (canSignupActivityIds.Count > 0)
            {
                var now = DateTime.Now;

                var needCheckSignupLimitActivityIds = new List<int>();
                // 过滤掉当前可报名的活动编号，可报名的无需更新
                var validCanSignupActivityIds = canSignupActivityIds.Where(i =>
                {
                    var activityInfo = activityInfos.FirstOrDefault(a => a.id == i);
                    if (activityInfo == null) return false;
                    // 忽略非不可报名状态
                    if (activityInfo.signupState != 1) return false;
                    // 如果时间不满足或者自定义报名人数不满足 也忽略
                    if (activityInfo.signupStartAt > now || activityInfo.signupEndAt < now) return false;
                    if (activityInfo.signupCount == 0) return false;
                    if (activityInfo.signupCount > 0) needCheckSignupLimitActivityIds.Add(i);
                    return true;
                }).ToList();
                // 进一步统计报名人数并判断是否满足
                if (needCheckSignupLimitActivityIds.Count > 0)
                {
                    // 查出活动当前报名人数
                    var userCountStat = (await repository.QueryAsync<dynamic>(
                        "select activityId, count(1) as count from n_activity_signup_records where activityId in @activityIds and state=1",
                        new { activityIds = needCheckSignupLimitActivityIds }, conn)).ToList();
                    validCanSignupActivityIds = validCanSignupActivityIds.Where(i =>
                    {
                        var activityInfo = activityInfos.First(a => a.id == i);
                        var userCount = userCountStat.FirstOrDefault(s => s.activityId == i)?.count ?? 0;
                        return activityInfo.signupCount > userCount;
                    }).ToList();
                }
                if (validCanSignupActivityIds.Count > 0)
                {
                    await repository.QueryAsync<dynamic>(
                        $"update n_activity set signupState=0 where id in @ids", new
                        {
                            ids = validCanSignupActivityIds
                        }, conn, null, false);
                    await repository.QueryAsync<dynamic>($"insert into n_activity_signup_state_change(activityId, `event`, createAt) values (@activityId, @eventTxt, now())", validCanSignupActivityIds.Select(
                        i => new
                        {
                            activityId = i,
                            eventTxt = "开始报名"
                        }));
                }
            }
        }

        /// <summary>
        /// 更新邀请好友活动的统计值（各活动任务完成状态/排行数据）
        /// </summary>
        public static async Task UpdateActivityYqhyStatBySingleUser(this DbRESTFulRepository repository, long userId, IDbConnection conn)
        {
            // 如果邀请好友活动未超出领取时间，才需要更新排名数据
            var needUpdateActivities = (await repository.QueryAsync<dynamic>(
                @"select id, startTime, endTime, config, signupEnabled, rewardRule,hotValue
                        from n_activity where state=1 and type='yqhy' and startTime<now() and (latestReceiveTime is null or latestReceiveTime>now())",
                null, conn)).ToList();
            if (needUpdateActivities.Count == 0) return;
            //更新热度值
            List<ActivityHotVO> activityInfos = needUpdateActivities.Where(a => (DateTime)a.endTime >= DateTime.Now && (int)a.signupEnabled == 0).Select(e => new ActivityHotVO
            {
                id = e.id,
                userId = userId,
                oldHotValue = e.hotValue,
                signupEnabled = (int)e.signupEnabled
            }).ToList();
            //活动参与热度记录
            await AddActivityHotRecords(repository, activityInfos, conn);
            var activityIds = needUpdateActivities.Where(e => e.signupEnabled == 1).Select(e => (int)e.id).ToList();
            var signupTimeDic = new Dictionary<int, DateTime>();
            // 如果启用报名的，则需要过滤掉未报名活动
            if (activityIds.Count > 0)
            {
                var validActivityInfos = (await repository.QueryAsync<dynamic>(
                    $"select activityId, createAt from n_activity_signup_records where activityId in @activityIds and userId={userId} and state=1",
                    new
                    {
                        activityIds
                    }, conn)).ToList();
                validActivityInfos.ForEach(e =>
                {
                    signupTimeDic[(int)e.activityId] = (DateTime)e.createAt;
                });
                var validActivityIds = validActivityInfos.Select(e => (int)e.activityId).ToList();
                needUpdateActivities = needUpdateActivities
                    .Where(e => activityIds.All(i => i != e.id) || validActivityIds.Any(i => i == e.id))
                    .ToList();
            }
            if (needUpdateActivities.Count == 0) return;
            var typedActivitiesDic = new Dictionary<int, ActivityYqhyConfig>();
            var activitiesDic = new Dictionary<int, dynamic>();
            var allRewardIds = new List<int>();
            var minTime = DateTime.MaxValue;
            var maxTime = DateTime.MinValue;
            var now = DateTime.Now;
            foreach (var activity in needUpdateActivities)
            {
                var config = JsonConvert.DeserializeObject<ActivityYqhyConfig>((string)activity.config);
                typedActivitiesDic[activity.id] = config;
                activitiesDic[activity.id] = activity;

                allRewardIds.AddRange(config.rewardIds);

                if (activity.startTime < minTime) minTime = activity.startTime;
                if (activity.endTime > maxTime) maxTime = activity.endTime;
            }
            // 统计此用户此期间所有的有效的邀请记录
            var records = (await repository.QueryAsync<dynamic>(
                $"select createAt, activeAt, hasProfit from n_user_invitation_record where userId={userId} and state=1 and invalid=0 and (createAt>=@minTime and createAt<=@maxTime) and (activeAt>=@minTime and activeAt<=@maxTime)",
                new { minTime, maxTime }, conn)).ToList();
            // 统计不同活动用户成功邀请次数
            var countDic = new Dictionary<int, int>();
            var lastCompletedTime = new Dictionary<int, DateTime>();
            records.ForEach(r =>
            {
                needUpdateActivities.ForEach(a =>
                {
                    var aid = (int)a.id;
                    var config = typedActivitiesDic[aid];
                    var startTime = a.startTime;
                    if (signupTimeDic.ContainsKey(aid) && signupTimeDic[aid] > startTime)
                    {
                        startTime = signupTimeDic[aid];
                    }
                    // 如果配置不允许获利邀请计入且当前条目是获利，则不计入
                    if ((!config.ignoreProfit || r.hasProfit == 0) && (a.endTime == null || a.endTime >= r.activeAt) && startTime <= r.activeAt)
                    {
                        if (countDic.ContainsKey(aid))
                        {
                            countDic[aid]++;
                        }
                        else
                        {
                            countDic[aid] = 1;
                        }

                        if (!lastCompletedTime.ContainsKey(aid) || lastCompletedTime[aid] < r.activeAt)
                        {
                            lastCompletedTime[aid] = r.activeAt;
                        }
                    }
                });
            });
            // 更新奖励状态记录
            if (allRewardIds.Count > 0)
            {
                var completed = new List<dynamic>();
                var uncompleted = new List<int>();
                // 查出所有活动的奖励配置
                var rewards = await repository.QueryAsync<dynamic>(
                    "select id, activityId, requirement from n_activity_reward where id in @ids and invalid=0 order by displayOrder asc",
                    new { ids = allRewardIds }, conn);
                // 用于设置仅发最后一个任务的奖励
                var activityIdHashSet = new HashSet<int>();
                // 检测各活动用户奖励是否达标
                rewards.ForEach(r =>
                {
                    int requirement = int.Parse(r.requirement);
                    int aid = (int)r.activityId;
                    var activityInfo = activitiesDic[aid];
                    var count = countDic.ContainsKey(aid) ? countDic[aid] : 0;
                    var time = lastCompletedTime.ContainsKey(aid) ? lastCompletedTime[aid] : now;
                    if (requirement <= count)
                    {
                        // 如果活动设置的是只能领取最后奖励，则需要将除最高任务的其他任务设置成未达成
                        if (activityInfo.rewardRule == 1)
                        {
                            if (!activityIdHashSet.Contains(aid))
                            {
                                completed.Add(new
                                {
                                    rewardId = r.id,
                                    r.activityId,
                                    latestCompleteAt = time
                                });
                                activityIdHashSet.Add(aid);
                            }
                            else
                            {
                                uncompleted.Add(r.id);
                            }
                        }
                        else
                        {
                            completed.Add(new
                            {
                                rewardId = r.id,
                                r.activityId,
                                latestCompleteAt = time
                            });
                        }
                    }
                    else
                    {
                        uncompleted.Add(r.id);
                    }
                });
                if (completed.Count > 0)
                {
                    await repository.QueryAsync<dynamic>(@$"insert into n_activity_reward_user_state
                        (userId, rewardId, activityId, state, latestCompleteAt) values
                        ({userId}, @rewardId, @activityId, 0, @latestCompleteAt)
                        ON DUPLICATE KEY update state=if(state=-1, 0, state), latestCompleteAt=if(state=-1, @latestCompleteAt, latestCompleteAt)",
                        completed, conn, null, false);
                }
                if (uncompleted.Count > 0)
                {
                    await repository.QueryAsync<dynamic>(@$"update n_activity_reward_user_state
                        set state=-1 where userId={userId} and rewardId in @ids and state=0", new { ids = uncompleted }, conn, null, false);
                }
            }

            if (countDic.Count > 0)
            {
                // 更新排行数据
                var rankingdata = countDic.Select(e => new
                {
                    activityId = e.Key,
                    score = e.Value,
                    lastRecordTime = lastCompletedTime.ContainsKey(e.Key) ? lastCompletedTime[e.Key] : now
                });
                await repository.QueryAsync<dynamic>($@"insert into n_activity_ranking
                        (activityId, userId, score, lastRecordTime) values
                        (@activityId, {userId}, @score, @lastRecordTime)
                        ON DUPLICATE KEY update score=@score, lastRecordTime=@lastRecordTime", rankingdata, conn, null, false);
            }

            // 更新报名状态
            if (allRewardIds.Count > 0)
            {
                await repository.UpdateActivitySignupState(allRewardIds, conn);
            }
        }

        /// <summary>
        /// 更新每日话题活动的统计值（各活动任务完成状态/排行数据）
        /// </summary>
        public static async Task UpdateActivityMrhtStatBySinglePost(this DbRESTFulRepository repository, long postId,
            IDbConnection conn)
        {
            // 如果每日话题活动未超出领取时间，才需要更新排名数据
            var needUpdateActivities = (await repository.QueryAsync<dynamic>(
                "select id, startTime, endTime, config, signupEnabled, rewardRule,hotValue from n_activity where type='mrht' and state=1 and startTime<now() and (latestReceiveTime is null or latestReceiveTime>now())",
                null, conn)).ToList();
            if (needUpdateActivities.Count == 0) return;
            var postInfo = await repository.QuerySingleOrDefaultAsync<dynamic>($"select userId, categoryType, originalTopicNames, createAt from n_post where id={postId}", null, conn);
            if (postInfo == null) return;
            var userId = (long)postInfo.userId;
            //更新热度值
            List<ActivityHotVO> activityInfos = needUpdateActivities.Where(a => (DateTime)a.endTime >= DateTime.Now && (int)a.signupEnabled == 0).Select(e => new ActivityHotVO
            {
                id = e.id,
                userId = userId,
                oldHotValue = e.hotValue,
                signupEnabled = (int)e.signupEnabled
            }).ToList();
            //活动参与热度记录
            await AddActivityHotRecords(repository, activityInfos, conn);
            {
                var activityIds = needUpdateActivities.Where(e => e.signupEnabled == 1).Select(e => (int)e.id).ToList();
                // 如果启用报名的，则需要过滤掉未报名活动
                if (activityIds.Count > 0)
                {
                    var validActivityIds = (await repository.QueryAsync<int>(
                        $"select activityId from n_activity_signup_records where activityId in @activityIds and userId={userId} and state=1",
                        new
                        {
                            activityIds
                        }, conn)).ToList();
                    needUpdateActivities = needUpdateActivities
                        .Where(e => !activityIds.Contains(e.id) || validActivityIds.Contains(e.id))
                        .ToList();
                }
            }
            if (needUpdateActivities.Count == 0) return;
            var topicNames = ((string)postInfo.originalTopicNames).Split('\n', StringSplitOptions.RemoveEmptyEntries);
            if (topicNames.Length == 0) return;
            var topicIds = (await repository.QueryAsync<int>("select id from n_topic where title in @names",
                new { names = topicNames }, conn)).ToList();
            if (topicIds.Count == 0) return;
            var createDate = ((DateTime)postInfo.createAt).Date;
            // 筛选出此文章话题相关的所有活动
            needUpdateActivities = needUpdateActivities.Where(e =>
            {
                var config = JsonConvert.DeserializeObject<ActivityMrhtConfig>((string)e.config);
                if (config.topics == null) return false;
                var validTopicId = config.topics.LastOrDefault(i => i.date.Date <= createDate && i.topicId > 0)
                    ?.topicId ?? 0;
                return validTopicId > 0 && topicIds.Contains(validTopicId);
            }).ToList();
            if (needUpdateActivities.Count == 0) return;
            var relativeActivityIds = needUpdateActivities.Select(e => e.id).ToList();
            // 找出此用户在所有有效每日话题中的活动记录
            var allRelativeRecords = (await repository.QueryAsync<dynamic>(
                $"select activityId, `date`, topicId, postId, createAt from n_activity_mrht_records where userId={userId} and state=1 and activityId in @activityIds",
                new { activityIds = relativeActivityIds }, conn)).ToList();
            if (allRelativeRecords.Count == 0) return;
            // 查出相关活动的奖励配置列表
            var rewards = (await repository.QueryAsync<dynamic>(
                    "select id, activityId, requirement, displayOrder from n_activity_reward where activityId in @activityIds and invalid=0 order by displayOrder asc",
                    new { activityIds = relativeActivityIds }, conn))
                .Select(e => new { e.id, e.activityId, requirement = int.Parse(e.requirement), e.displayOrder }).ToList();
            if (rewards.Count == 0) return;
            // 查出已达成和未达成的任务
            var completedRecords =
                (await repository.QueryAsync<dynamic>(
                    $"select rewardId, latestCompleteAt from n_activity_reward_user_state where userId={userId} and rewardId in @rewardIds and state in (0, 1)",
                    new { rewardIds = rewards.Select(e => e.id) }, conn)).ToList();
            var completed = completedRecords.Select(e => (int)e.rewardId).ToList();
            var uncompleted = rewards.Where(e => !completed.Contains(e.id));
            var insertRecords = new List<dynamic>(); // 待插入或更新的达成记录(除去了最高任务奖励类型)
            var singleRewardInsertRecords = new List<dynamic>(); // 待插入或更新的达成记录(仅包含最高任务奖励类型)
            // 判断达成情况
            uncompleted.ForEach(e =>
            {
                var curActivityRecords = allRelativeRecords.Where(i => i.activityId == e.activityId).ToList();
                // 查出此任务所有的完成的记录数量
                var dates = curActivityRecords.Select(i => i.date).Distinct().OrderBy(d => d).ToList();
                var count = dates.Count;
                if (count >= e.requirement && e.requirement > 0)
                {
                    // 达成活动的日期
                    var date = dates[e.requirement - 1];
                    // 找出达成的那天最早的发布时间
                    var latestCompleteAt = curActivityRecords.Where(i => i.date == date).Select(i => i.date).Min();
                    // 添加到更新列表中
                    insertRecords.Add(new { rewardId = e.id, e.activityId, latestCompleteAt });
                }
            });

            // 如果活动设置的是只能领取最后奖励，则需要将除最高任务的其他任务设置成未达成
            var singleRewardActivityList = needUpdateActivities.Where(e => e.rewardRule == 1).ToList();
            if (singleRewardActivityList.Count > 0)
            {
                var set = new HashSet<int>();
                rewards.ForEach(e =>
                {
                    if (singleRewardActivityList.All(a => a.id != e.activityId)) return;
                    var existRecord = completedRecords.FirstOrDefault(r => r.rewardId == e.id);
                    if (existRecord == null) existRecord = insertRecords.FirstOrDefault(r => r.rewardId == e.id);
                    if (existRecord == null) return;
                    if (set.Contains(e.activityId)) return;
                    set.Add(e.activityId);
                    singleRewardInsertRecords.Add(new
                    {
                        rewardId = e.id,
                        e.activityId,
                        existRecord.latestCompleteAt
                    });
                });

                // 先在更新列表中移除只领一个奖励的任务
                insertRecords = insertRecords.Where(e => singleRewardActivityList.All(a => a.id != e.activityId))
                    .ToList();
            }

            // 更新此用户所有有效的每日话题活动总参与次数
            var rankingdata = new List<dynamic>();
            allRelativeRecords.GroupBy(e => e.activityId).ForEach(group =>
            {
                var activityId = group.Key;
                var list = group.ToList();
                var sgroup = list.GroupBy(i => i.date);
                var count = sgroup.Count();
                var minTime = sgroup.OrderBy(m => m.Key).Last().First().createAt;
                rankingdata.Add(new
                {
                    activityId,
                    score = count,
                    lastRecordTime = minTime
                });
            });

            List<int> validUpdatedRecordIds = new List<int>();

            if (insertRecords.Count > 0)
            {
                await repository.QueryAsync<dynamic>(@$"insert into n_activity_reward_user_state
                        (userId, rewardId, activityId, state, latestCompleteAt) values
                        ({userId}, @rewardId, @activityId, 0, @latestCompleteAt)
                        ON DUPLICATE KEY update state=if(state=-1, 0, state), latestCompleteAt=if(state=-1, @latestCompleteAt, latestCompleteAt)",
                    insertRecords, conn, null, false);
                validUpdatedRecordIds.AddRange(insertRecords.Select(e => (int)e.rewardId));
            }
            if (singleRewardActivityList.Count > 0)
            {
                // 如果活动设置的是只能领取最后奖励，先重置非达成的状态，然后再插入或更新达成的状态
                var activityIds = singleRewardActivityList.Select(a => a.id);
                dynamic rewardIds = singleRewardInsertRecords.Count > 0
                    ? singleRewardInsertRecords.Select(e => e.rewardId)
                    : null;
                await repository.QueryAsync<dynamic>(
                    $"update n_activity_reward_user_state set state=-1 where activityId in @activityIds and userId={userId} [and rewardId not in @rewardIds]", new
                    {
                        activityIds,
                        rewardIds
                    }, conn, null, false);
                if (singleRewardInsertRecords.Count > 0)
                {
                    await repository.QueryAsync<dynamic>(@$"insert into n_activity_reward_user_state
                        (userId, rewardId, activityId, state, latestCompleteAt) values
                        ({userId}, @rewardId, @activityId, 0, @latestCompleteAt)
                        ON DUPLICATE KEY update state=if(state=-1, 0, state), latestCompleteAt=if(state=-1, @latestCompleteAt, latestCompleteAt)",
                        singleRewardInsertRecords, conn, null, false);
                    validUpdatedRecordIds.AddRange(singleRewardInsertRecords.Select(e => (int)e.rewardId));
                }
            }
            if (rankingdata.Count > 0)
            {
                await repository.QueryAsync<dynamic>($@"insert into n_activity_ranking
                        (activityId, userId, score, lastRecordTime) values
                        (@activityId, {userId}, @score, @lastRecordTime)
                        ON DUPLICATE KEY update score=@score, lastRecordTime=@lastRecordTime", rankingdata, conn, null, false);
            }

            // 更新报名状态
            if (validUpdatedRecordIds.Count > 0)
            {
                await repository.UpdateActivitySignupState(validUpdatedRecordIds, conn);
            }
        }

        /// <summary>
        /// 活动参与热度记录
        /// </summary>
        /// <param name="repository"></param>
        /// <param name="userId"></param>
        /// <param name="hotInfos"></param>
        /// <param name="conn"></param>
        /// <returns></returns>
        public static async Task AddActivityHotRecords(this DbRESTFulRepository repository, List<ActivityHotVO> hotInfos, IDbConnection conn)
        {
            if (hotInfos != null && hotInfos.Count > 0)
            {
                //所有活动id
                var ids = hotInfos.Select(s => s.id);
                //该用户已经参与活动已经加过热度了
                var activityIds = await repository.QueryAsync<int>(
                 $"select activityId from n_activity_hot_records where activityId in @ids and userId=@userId limit  1", new { ids, hotInfos[0].userId },
                 conn, null, false);
                if (activityIds != null && activityIds.Count() > 0)
                {
                    hotInfos = hotInfos.Where(s => !activityIds.ToList().Contains(s.id)).ToList();
                }
                if (hotInfos != null && hotInfos.Count > 0)
                {
                    //报名：每个账号报名成功时，随机加1～10；
                    //热度：每个账号完成每个活动的第1次任务时，随机加5～15
                    hotInfos.ForEach(item => { item.addHotValue = item.signupEnabled == 1 ? new Random().Next(1, 10) : new Random().Next(5, 15); });
                    await repository.QueryAsync<dynamic>(
                              "update n_activity set hotValue=hotValue+@addHotValue where id=@id;", hotInfos,
                              conn, null, false);
                    await repository.QueryAsync<dynamic>(
                        $@"insert into n_activity_hot_records(activityId,userId, oldHotValue,addHotValue, createAt)
                        values (@id,@userId, @oldHotValue,@addHotValue, now())", hotInfos, conn, null, false);
                }
            }
        }
    }
}
