using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using TEAMModelOS.SDK.Models.Cosmos;
using TEAMModelOS.SDK.Extension;
using Azure.Cosmos;
using TEAMModelOS.SDK.DI;
using HTEXLib.COMM.Helpers;
using System.Text;
using TEAMModelOS.SDK.Models;
using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
using StackExchange.Redis;
using TEAMModelOS.SDK.Models.Cosmos.Common;

namespace TEAMModelOS.Services.Common
{
    public static class ActivityStudentService
    {

       
        public static async Task<int> Decide(JsonElement request,AzureCosmosFactory _azureCosmos,AzureRedisFactory _azureRedis,string userid ) {

            DateTimeOffset now = DateTimeOffset.UtcNow;
            long curr = now.ToUnixTimeMilliseconds();
            byte msgid = 0;//0投票失败，1投票成功，2不在时间范围内，3不在发布范围内，4投票周期内重复投票，5周期内的可投票数不足,6未设置投票项
            //活动id
            if (!request.TryGetProperty("id", out JsonElement id)) {
                return msgid;
            }
            //活动分区
            if (!request.TryGetProperty("code", out JsonElement code)) {
                return msgid;
            }
            Dictionary<string, int> option = new Dictionary<string, int>();
            if (request.TryGetProperty("option", out JsonElement joption))
            {
                option = joption.ToObject<Dictionary<string, int>>();
                if (option.IsEmpty())
                {
                    msgid = 6;
                    return msgid; 
                }
            }
            else
            {
                return msgid;
            }
         
            try
            {
                //1.再次检查投票
                var client = _azureCosmos.GetCosmosClient();
                Vote vote = null;
                ///TODO 检查是否在投票范围内，包括在tmdids 及班级  但是需要处理认证金钥中的班级问题
                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryIterator<Vote>(queryText: $"select c.id,c.code , c.progress,c.times,c.voteNum,c.startTime,c.endTime from c where c.id = '{id}'",
                    requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{code}") }))
                {
                    vote = item;
                    break;
                }
                if (vote != null)
                {
                    //判断投票时间是否在起止时间内
                    if (curr >= vote.startTime && curr <= vote.endTime)
                    {
                        string Field = "";
                        RedisValue value;
                        switch (vote.times) {
                            case "once":
                                // //如果是只能投票一次的活动则直接获取Redis的第一条 只能投一次
                                Field = $"{userid}-once";
                                HashEntry[] values = _azureRedis.GetRedisClient(8).HashGetAll($"Vote:Record:{vote.id}");
                                if (values != null  && values.Length > 0)
                                {
                                    value = new RedisValue();
                                    foreach (var val in values) {
                                        if (val.Name.ToString() == Field) {
                                            value = val.Value;
                                            break;
                                        }
                                    }
                                    msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid,vote.times, "once");
                                }
                                else
                                {
                                    msgid = await VoteIng(vote, new RedisValue(), msgid, option, Field, curr, _azureRedis, userid, vote.times, "once");
                                }
                                break;
                            case "day": //周期内每天
                                Field = $"{userid}-day-{now.ToString("yyyyMMdd")}";
                                value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}", Field);
                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis,userid, vote.times, now.ToString("yyyyMMdd"));
                                break;
                            case "week": //自然周
                                int week = GetWeek(now);
                                Field = $"{userid}-week-{now.ToString("yyyy")}{week}";
                                value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}", Field);
                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid, vote.times,$"{now.ToString("yyyy")}{week}"); 
                                break;
                            case "month":  //月份
                                Field = $"{userid}-month-{now.ToString("yyyyMM")}";
                                value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}", Field);
                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid, vote.times, now.ToString("yyyyMM")); 
                                break;
                            case "year"://年份
                                Field = $"{userid}-year-{now.ToString("yyyy")}";
                                value = _azureRedis.GetRedisClient(8).HashGet($"Vote:Record:{vote.id}", Field);
                                msgid = await VoteIng(vote, value, msgid, option, Field, curr, _azureRedis, userid, vote.times, now.ToString("yyyy"));
                                break;
                        }
                    }
                    else
                    {
                        msgid = 2;
                    }
                }
            }
            catch (Exception e)
            {
                throw new Exception(e.StackTrace);
            }
            return msgid;
        }

      

        public static async Task<byte> VoteIng(Vote vote, RedisValue value, byte msgid, Dictionary<string, int> option, string Field, long curr, AzureRedisFactory _azureRedis,string userid,string times,string endpoint)
        {
            if (!value.IsNullOrEmpty)
            {
                VoteRecord record=value.ToString().ToObject<VoteRecord>();
                int addCount = 0;
                foreach (var op in option) {
                    addCount +=op.Value;
                }
                int crdCount = 0;
                foreach (var op in record.opt)
                {
                    crdCount += op.Value;
                }
                //处理记录投票+当前设置的投票是否小于等于周期内最大投票数
                if (addCount + crdCount <= vote.voteNum)
                {
                    foreach (var op in option)
                    {
                        if (record.opt.ContainsKey(op.Key))
                        {
                            record.opt[op.Key] = record.opt[op.Key] + op.Value;
                        }
                        else {
                            record.opt.Add(op.Key, op.Value);
                        }
                    }
                    record.time = curr;
                    record.userid = userid;
                    record.times = times;
                    record.endpoint = endpoint;
                    //保存投票记录
                    bool status = await _azureRedis.GetRedisClient(8).HashSetAsync($"Vote:Record:{vote.id}", Field, record.ToJsonString());
                    //单独保存每个人方便查询的记录
                    bool stuallstatus = await _azureRedis.GetRedisClient(8).HashSetAsync($"Vote:Record:{vote.id}:{userid}", Field, record.ToJsonString());
                    //当前投票分组计数存入活动的Redis
                    foreach (var opt in option)
                    {
                        await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Vote:Count:{vote.id}", opt.Key, opt.Value);
                    }
                    msgid = 1;
                }
                else
                {
                    msgid = 5;
                }
            }
            else
            {
                if (option.Count <= vote.voteNum)
                {
                    //保存投票记录
                    VoteRecord record = new VoteRecord { opt = option, time = curr, userid = userid ,times=times,endpoint=endpoint};
                    bool status = await _azureRedis.GetRedisClient(8).HashSetAsync($"Vote:Record:{vote.id}", Field, record.ToJsonString());
                    //单独保存每个人方便查询的记录
                    bool stuallstatus = await _azureRedis.GetRedisClient(8).HashSetAsync($"Vote:Record:{vote.id}:{userid}", Field, record.ToJsonString());
                    //当前投票分组计数存入活动的Redis
                    foreach (var opt in option)
                    {
                        await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Vote:Count:{vote.id}", opt.Key, opt.Value);
                    }
                    if (status)
                    {
                        msgid = 1;
                    }
                }
                else {
                    msgid = 5;
                }
            }
            return msgid;
        }
        /// <summary>
        /// 获取时间的在当年的第几周
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static int GetWeek(DateTimeOffset dt)
        {
            DateTimeOffset time = Convert.ToDateTime(dt.ToString("yyyy") + "-01-01");
            TimeSpan ts = dt - time;
            int iii = (int)time.DayOfWeek;
            int day = int.Parse(ts.TotalDays.ToString("F0"));
            if (iii == 0)
            {
                day--;
            }
            else
            {
                day = day - (7 - iii) - 1;
            }
            int week = ((day + 7) / 7) + 1;
            return week;
        }
        public static async Task<(List<StuActivity> datas, string continuationToken)> FindActivity(JsonElement request, string id, string school, AzureCosmosFactory _azureCosmos, AzureRedisFactory azureRedis)
        {

            if (string.IsNullOrWhiteSpace(id))
            {
                if (request.TryGetProperty("userid", out JsonElement userid))
                {
                    if (!userid.ValueKind.Equals(JsonValueKind.Undefined) && !userid.ValueKind.Equals(JsonValueKind.Null) && userid.ValueKind.Equals(JsonValueKind.String))
                    {
                        id = userid.GetString();
                    }
                }
            }


            if (string.IsNullOrWhiteSpace(school))
            {
                if (request.TryGetProperty("school", out JsonElement schooljson))
                {
                    if (!schooljson.ValueKind.Equals(JsonValueKind.Undefined) && !schooljson.ValueKind.Equals(JsonValueKind.Null) && schooljson.ValueKind.Equals(JsonValueKind.String))
                    {
                        school = schooljson.GetString();
                    }
                }
            }

            /// tmdid, schoolid
            var userType = "tmdid";
            if (request.TryGetProperty("userType", out JsonElement usertype))
            {
                if (!usertype.ValueKind.Equals(JsonValueKind.Undefined) && !usertype.ValueKind.Equals(JsonValueKind.Null) && usertype.ValueKind.Equals(JsonValueKind.String))
                {
                    userType = usertype.GetString();
                }
            }

            //开始时间，默认最近三十天
            var stimestamp = DateTimeOffset.UtcNow.AddDays(-30).ToUnixTimeMilliseconds();
            if (request.TryGetProperty("stime", out JsonElement stime))
            {
                if (!stime.ValueKind.Equals(JsonValueKind.Undefined) && !stime.ValueKind.Equals(JsonValueKind.Null) && stime.TryGetInt64(out long data))
                {
                    stimestamp = data;
                }
            }
            string stimesql = $" c.startTime >= {stimestamp}  ";
            //默认当前时间，  未开始的不能查询
            var etimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
            string etimesql = $" and c.startTime <= {etimestamp}   ";
           
            var typesql = "";
            if (request.TryGetProperty("type", out JsonElement type))
            {

                if (!type.ValueKind.Equals(JsonValueKind.Undefined) && !type.ValueKind.Equals(JsonValueKind.Null) && type.ValueKind.Equals(JsonValueKind.String))
                {
                    typesql = $" and c.type='{type}' ";
                }
            }
            string continuationToken = null;
            //默认不指定返回大小
            int? topcout = null;
            if (request.TryGetProperty("count", out JsonElement jcount))
            {
                if (!jcount.ValueKind.Equals(JsonValueKind.Undefined) && !jcount.ValueKind.Equals(JsonValueKind.Null) && jcount.TryGetInt32(out int data))
                {
                    topcout = data;
                }
            }
            //是否需要进行分页查询，默认不分页
            bool iscontinuation = false;
            if (topcout != null && topcout.Value > 0)
            {
                iscontinuation = true;
            }
            //如果指定了返回大小
            if (request.TryGetProperty("continuationToken", out JsonElement token))
            {
                //指定了cancellationToken continuationSchool
                if (!token.ValueKind.Equals(JsonValueKind.Null) && token.ValueKind.Equals(JsonValueKind.String))
                {
                    continuationToken = token.GetString();

                }
            }
            ////个人tmdid
            //string joinSqlTmdids = $"join A0 in c.tmdids";
            //string andSqlTmdids = $"   A0 in('{id}')";
            ////班级
            //string joinSqlClasses = "";
            //string andSqlClasses = "";
            //List<string> classes = null;
            //if (request.TryGetProperty("classes", out JsonElement jclasses))
            //{
            //    if (jclasses.ValueKind is JsonValueKind.Array)
            //    {
            //        classes = jclasses.ToObject<List<string>>();
            //        if (classes.IsNotEmpty())
            //        {
            //            joinSqlClasses = " join A1 in c.classes ";
            //            List<string> sqlList = new List<string>();
            //            classes.ForEach(x => { sqlList.Add($" '{x}' "); });
            //            string sql = string.Join(" , ", sqlList);
            //            andSqlClasses = $"   A1 in ({sql}) ";
            //        }
            //    }
            //}
            //string tgSql = "";
            //if (!string.IsNullOrWhiteSpace(joinSqlClasses))
            //{
            //    tgSql = $" and ({andSqlTmdids} or  {andSqlClasses } )";
            //}
            //else
            //{
            //    tgSql = $" and {andSqlTmdids}";
            //}
            //科目
            string joinSqlSubjects = "";
            string andSqlSubjects = "";
            if (request.TryGetProperty("subjects", out JsonElement jsubjects))
            {
                if (jsubjects.ValueKind is JsonValueKind.Array)
                {
                    List<string> subjects = jsubjects.ToObject<List<string>>();
                    if (subjects.IsNotEmpty())
                    {
                        joinSqlSubjects = " join A2 in c.subjects ";
                        List<string> sqlList = new List<string>();
                        subjects.ForEach(x => { sqlList.Add($" '{x}' "); });
                        string sql = string.Join(" , ", sqlList);
                        andSqlSubjects = $" and A2 in ({sql}) ";
                    }
                }
            }
            List<StuActivity> datas = new List<StuActivity>();
            var client = _azureCosmos.GetCosmosClient();
            if (!string.IsNullOrWhiteSpace(school))
            {
                string containerId = "Student";
                string PartitionKey = $"Activity-{school}-{id}";
                /// tmdid, schoolid
                if (userType.Equals("tmdid")) {
                    containerId = "Teacher";
                    PartitionKey = $"Activity-{id}";

                }
                string querySchool = $" SELECT distinct  value c   FROM c   {joinSqlSubjects}  where {stimesql}  {etimesql} and c.pk='Activity'   {typesql}  {andSqlSubjects}  ";

                //查询数据归属学校的
                await foreach (var item in client.GetContainer("TEAMModelOS", containerId).GetItemQueryStreamIterator(querySchool, continuationToken: continuationToken,
                    requestOptions: new QueryRequestOptions() { MaxItemCount = topcout, PartitionKey = new PartitionKey(PartitionKey) }))
                {
                    using var json = await JsonDocument.ParseAsync(item.ContentStream);
                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                    {
                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
                        {
                            datas.Add(obj.ToObject<StuActivity>());
                        }
                        //如果需要分页则跳出
                        if (iscontinuation)
                        {
                            continuationToken = item.GetContinuationToken();
                            break;
                        }
                    }
                }
            }
            return (datas, continuationToken);
        }

        
        public static async Task<int> Answer(JsonElement request, AzureCosmosFactory _azureCosmos, AzureRedisFactory azureRedis, string userid, AzureStorageFactory _azureStorage)
        {

            DateTimeOffset now = DateTimeOffset.UtcNow;
            long curr = now.ToUnixTimeMilliseconds();
            byte msgid = 0;//
            //活动id
            if (!request.TryGetProperty("id", out JsonElement id))
            {
                return msgid;
            }
            //活动分区
            if (!request.TryGetProperty("code", out JsonElement code))
            {
                return msgid;
            }

            try
            {
                //1.再次检查投票
                var client = _azureCosmos.GetCosmosClient();
                Survey survey = null;
                ///TODO 检查是否在投票范围内，包括在tmdids 及班级  但是需要处理认证金钥中的班级问题
                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryIterator<Survey>(queryText: $"select c.id,c.owner,c.scope, c.code ,c.creatorId,c.answers ,c.school , c.progress,c.times,c.startTime,c.endTime from c where c.id = '{id}'",
                    requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"{code}") }))
                {
                    survey = item;
                    break;
                }
                if (survey != null)
                {
                    //判断投票时间是否在起止时间内
                    if (curr >= survey.startTime && curr <= survey.endTime)
                    {
                        if (request.TryGetProperty("record", out JsonElement record)) 
                        {
                            var recs = record.ToObject<List<List<string>>>();
                            if (recs.IsNotEmpty() && recs.Count == survey.answers.Count)
                            {
                                //处理问卷调查表的每一题选项数
                               // List<Task<string>> tasks = new List<Task<string>>();
                                for (int index = 0; index < recs.Count; index++) {
                                    Dictionary<string, int> dict = new Dictionary<string, int>();
                                    if (recs[index].IsNotEmpty()) {
                                        recs[index].ForEach(x => {
                                            if (survey.answers[index].Contains(x))
                                            {
                                                if (dict.ContainsKey(x))
                                                {
                                                    dict[x] = dict[x] + 1;
                                                }
                                                else {
                                                    dict[x] = 1;
                                                }
                                            }
                                            else {
                                                if (dict.ContainsKey("other"))
                                                {
                                                    dict["other"] = dict["other"] + 1;
                                                }
                                                else
                                                {
                                                    dict["other"] = 1;
                                                }
                                                //这里暂不处理， 结算再处理other 
                                                //  tasks.Add(_azureStorage.UploadFileByContainer(survey.owner,new { other=x, userid, time =curr }.ToJsonString(), "survey", $"{survey.id}/other/{index}/{userid}.json", false));
                                            }
                                        });
                                    }
                                    var value= azureRedis.GetRedisClient(8).HashGet($"Survey:Record:{survey.id}",index);
                                    if (value != default && !value.IsNullOrEmpty)
                                    {
                                        Dictionary<string, int> dt = value.ToString().ToObject<Dictionary<string, int>>();
                                        foreach (var kp in dict)
                                        {   //不建议放在reids
                                            if (dt.ContainsKey(kp.Key))
                                            {
                                                dt[kp.Key] = dt[kp.Key] + kp.Value;
                                            }
                                            else
                                            {
                                                dt.Add(kp.Key, kp.Value);
                                            }
                                        }
                                        await azureRedis.GetRedisClient(8).HashSetAsync($"Survey:Record:{survey.id}", index, dt.ToJsonString());
                                    }
                                    else {
                                       await azureRedis.GetRedisClient(8).HashSetAsync($"Survey:Record:{survey.id}", index, dict.ToJsonString());
                                    }
                                }

                                //处理other ，这里暂不处理， 结算再处理other 
                                //await Task.WhenAll(tasks);
                                //保存当前提交人的记录

                                string blobcntr = null;
                                if (survey.scope == "school")
                                {
                                    blobcntr = survey.school;
                                }
                                else if (survey.scope == "private")
                                {
                                    blobcntr = survey.creatorId;
                                }
                                await _azureStorage.UploadFileByContainer(blobcntr, new SurveyRecord { ans= recs, userid=userid, time = curr }.ToJsonString(), "survey", $"{survey.id}/urecord/{userid}.json");
                                await azureRedis.GetRedisClient(8).SetAddAsync($"Survey:Submit:{survey.id}", userid);
                                msgid = 1;
                            }
                            else {
                                //提交的作答不符合问卷的答案长度。
                                msgid = 3;
                            }
                        }
                        
                    }
                    else
                    {
                        msgid = 2;
                    }
                }
            }
            catch (Exception e)
            {
                throw new Exception(e.StackTrace);
            }
            return msgid;
        }
        public class RdsRecord {
            public Dictionary<string, int> srecord { get; set; } = new Dictionary<string, int>();
            public Dictionary<string, string[]> urecord { get; set; } = new Dictionary<string, string[]>();
        }  
    }
}
