using Azure.Cosmos;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using TEAMModelOS.Models.Dto;
using TEAMModelOS.SDK.Models;
using TEAMModelOS.SDK;
using TEAMModelOS.SDK.Context.Constant.Common;
using TEAMModelOS.SDK.DI;
using TEAMModelOS.SDK.DI.AzureCosmos.Inner;
using TEAMModelOS.SDK.Extension;
using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
using TEAMModelOS.SDK.Helper.Common.StringHelper;
using TEAMModelOS.Models;
using Microsoft.Extensions.Options;
using TEAMModelOS.SDK.Models.Cosmos;
using Microsoft.AspNetCore.Authorization;
using TEAMModelOS.Filter;
using StackExchange.Redis;
using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
using TEAMModelOS.Services.Common;
using Azure.Messaging.ServiceBus;
using Microsoft.Extensions.Configuration;

namespace TEAMModelOS.Controllers.Learn
{
    /// <summary>
    /// 投票活动
    /// </summary>
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    //[Authorize(Roles = "IES5")]
    [Route("common/vote")]
    [ApiController]
    public class VoteController : ControllerBase
    {
        private readonly AzureRedisFactory _azureRedis;
        private readonly AzureCosmosFactory _azureCosmos;
        private readonly SnowflakeId _snowflakeId;
        private readonly AzureServiceBusFactory _serviceBus;
        private readonly DingDing _dingDing;
        private readonly Option _option;
        private readonly AzureStorageFactory _azureStorage;
        public IConfiguration _configuration { get; set; }

        public VoteController(AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option,
            AzureRedisFactory azureRedis, AzureStorageFactory azureStorage, IConfiguration configuration)
        {
            _azureCosmos = azureCosmos;
            _serviceBus = serviceBus;
            _snowflakeId = snowflakeId;
            _dingDing = dingDing;
            _option = option?.Value;
            _azureRedis = azureRedis;
            _azureStorage = azureStorage;
            _configuration = configuration;
        }
        /// <summary>
        /// 新增 或 修改投票活动
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("upsert")]
        [AuthToken(Roles = "teacher,admin")]
        public async Task<IActionResult> Upsert(Vote request)
        {
            try
            {
                //新增Vote
                var client = _azureCosmos.GetCosmosClient();
                request.code = request.pk + "-" + request.code;
                request.ttl = -1;
                long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                request.createTime = now;
               
                //如果设置的时间是小于当前时间则立即发布
                if (request.startTime <= 0) {
                    request.startTime = now;
                }
                if (string.IsNullOrEmpty(request.id))
                {
                   
                    request.id = Guid.NewGuid().ToString();
                    if (request.startTime > now)
                    {
                        request.progress = "pending";
                    }
                    else { 
                        request.progress = "going"; 
                    }
                    var messageBlob = new ServiceBusMessage();
                    if (request.scope.Equals("school"))
                    {
                        request.size = await _azureStorage.GetBlobContainerClient(request.school).GetBlobsSize($"vote/{request.id}");
                        messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "insert", root = $"vote/{request.id}", name = $"{request.school}" }.ToJsonString());                       
                    }
                    else
                    {
                        request.size = await _azureStorage.GetBlobContainerClient(request.creatorId).GetBlobsSize($"vote/{request.id}");
                        messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "insert", root = $"vote/{request.id}", name = $"{request.creatorId}" }.ToJsonString());
                    }
                    messageBlob.ApplicationProperties.Add("name", "BlobRoot");
                    var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
                    await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageBlob);
                    request = await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(request, new PartitionKey($"{request.code}"));
                }
                else
                {
                    var response = await client.GetContainer("TEAMModelOS", "Common").ReadItemStreamAsync(request.id, new PartitionKey($"{request.code}"));
                    var messageBlob = new ServiceBusMessage();
                    if (request.scope.Equals("school"))
                    {
                        request.size = await _azureStorage.GetBlobContainerClient(request.school).GetBlobsSize($"vote/{request.id}");
                        messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "update", root = $"vote/{request.id}", name = $"{request.school}" }.ToJsonString());
                    }
                    else
                    {
                        request.size = await _azureStorage.GetBlobContainerClient(request.creatorId).GetBlobsSize($"vote/{request.id}");
                        messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "update", root = $"vote/{request.id}", name = $"{request.creatorId}" }.ToJsonString());
                    }
                    messageBlob.ApplicationProperties.Add("name", "BlobRoot");
                    var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
                    await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageBlob);
                    if (response.Status == 200)
                    {
                        using var json = await JsonDocument.ParseAsync(response.ContentStream);
                        var info = json.ToObject<Vote>();
                        if (info.progress.Equals("going"))
                        {
                            return Ok(new { v = "活动正在进行中" });
                        }
                        if (request.startTime > now)
                        {
                            request.progress = "pending";
                        }
                        else
                        {
                            request.progress = "going";
                        }
                        request.progress = info.progress;
                        request = await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(request, info.id, new PartitionKey($"{info.code}"));
                    }
                    else
                    {
                        if (request.startTime > now)
                        {
                            request.progress = "pending";
                        }
                        else
                        {
                            request.progress = "going";
                        }
                        request = await client.GetContainer("TEAMModelOS", "Common").CreateItemAsync(request, new PartitionKey($"{request.code}"));
                    }
                }
                return Ok(new { vote = request });
            }
            catch (Exception e)
            {
                await _dingDing.SendBotMsg($"OS，{_option.Location}，common/vote/save()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
                return BadRequest(e.StackTrace);
            }
        }
        /// <summary>
        /// 查询投票活动,用于列表，编辑，查看
        /// </summary>
        /// <data>
        ///Vote-学校/教师编码  活动分区        !"code":"hbcn"/1606285227 
        ///时间筛选范围开始时间 默认30天之前   ?"stime":1608274766154  
        ///时间筛选范围结束时间 默认当前时间   ?"etime":1608274766666 
        ///每页大小     ?"count":10/null/Undefined  
        ///分页Token    ?"continuationToken":Undefined/null/"[{\"token\":\"+RID:~omxMAP3ipcSEEwAAAAAAAA==#RT:2#TRC:20#ISV:2#IEO:65551#QCF:1#FPC:AYQTAAAAAAAAiRMAAAAAAAA=\",\"range\":{\"min\":\"\",\"max\":\"FF\"}}]"
        /// 当前状态    ?"progress":Undefined/null/"" 表示两种状态都要查询/ "going"/"finish" 表示查询进行中/ 或者已完成 学生端只能查询正在进行或已经结束 going 已发布|finish 已结束  
        /// </data>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("find")]
        [AuthToken(Roles = "teacher,admin")]
        public async Task<IActionResult> Find(JsonElement requert)
        {
            try
            {
                //必须有学校或者教师编码
                if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
                //开始时间，默认最近三十天
                var stimestamp = DateTimeOffset.UtcNow.AddDays(-30).ToUnixTimeMilliseconds();
                if (requert.TryGetProperty("stime", out JsonElement stime)) {
                    if (!stime.ValueKind.Equals(JsonValueKind.Undefined)&&stime.TryGetInt64(out long data))
                    {
                        stimestamp = data;
                    };
                };
                //默认当前时间
                var etimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                if (requert.TryGetProperty("etime", out JsonElement etime))
                {
                    if (!etime.ValueKind.Equals(JsonValueKind.Undefined)&&etime.TryGetInt64(out long data))
                    {
                        etimestamp = data;
                    };

                };
                var progresssql = "";
                if (!requert.TryGetProperty("progress", out JsonElement progress))
                {

                    if (!progress.ValueKind.Equals(JsonValueKind.Undefined) && !progress.ValueKind.Equals(JsonValueKind.Null) && progress.ValueKind.Equals(JsonValueKind.String))
                    {
                        progresssql = $" and c.progress='{progresssql}' ";
                    }
                }
                string continuationToken = null;
                //默认不指定返回大小
                int? topcout=null;
                if (requert.TryGetProperty("count", out JsonElement jcount)) {
                    if(!jcount.ValueKind.Equals(JsonValueKind.Undefined) && jcount.TryGetInt32(out int data))
                    {
                        topcout = data;
                    }
                };
                //是否需要进行分页查询，默认不分页
                bool iscontinuation = false;
                //如果指定了返回大小
                if (requert.TryGetProperty("continuationToken", out JsonElement continuation))
                {
                    //指定了cancellationToken 表示需要进行分页
                    if (!continuation.ValueKind.Equals(JsonValueKind.Null) && !continuation.ValueKind.Equals(JsonValueKind.Undefined))
                    {
                        continuationToken = continuation.GetString();
                        iscontinuation = true;
                    }
                };
                List<object> votes = new List<object>();
                var client = _azureCosmos.GetCosmosClient();
             
                var query =$"select   c.id,c.name,c.code,c.startTime,c.endTime,c.progress from c where c.createTime >= {stimestamp} and c.createTime <= {etimestamp}  {progresssql } ";
                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryStreamIterator(queryText: query,
                    requestOptions: new QueryRequestOptions() {MaxItemCount = topcout, PartitionKey = new PartitionKey($"Vote-{code}") }))
                {
                    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())
                        {
                            votes.Add(obj.ToObject<JsonElement>());
                        }
                        //如果需要分页则跳出
                        if (iscontinuation) {
                            continuationToken = item.GetContinuationToken();
                            break;
                        }
                    }
                }
                return Ok(new { votes, continuationToken });
            }
            catch (Exception ex)
            {
                await _dingDing.SendBotMsg($"OS，{_option.Location}，common/vote/find()\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
                return BadRequest(ex.StackTrace);
            }
        }
        ///<summary>
        /// 查询投票活动,用于创建者列表，编辑，查看，投票人员查看
        /// </summary>
        /// <data>
        ///    ! "id":"3c075347-75ef-4bcb-ae03-68678d02d5ef",
        ///    ! "code":"Vote-hbcn"/"code":"Vote-1606285227"
        /// </data>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("find-id")]
        [AuthToken(Roles = "teacher,admin,student")]
        public async Task<IActionResult> FindById(JsonElement requert)
        {
            try
            {
                var client = _azureCosmos.GetCosmosClient();
                //活动id
                if (!requert.TryGetProperty("id", out JsonElement id)) return BadRequest();
                //活动分区
                if (!requert.TryGetProperty("code", out JsonElement code)) return BadRequest();
                Vote vote = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Vote>(id.GetString(), new PartitionKey($"{code}"));
                if (vote != null)
                {
                    
                    return Ok(new { vote });
                }
                else
                {
                    return BadRequest("id,code不存在！");
                }
            }
            catch (Exception ex)
            {
                await _dingDing.SendBotMsg($"OS，{_option.Location}，common/vote/find-id()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
                return BadRequest(ex.StackTrace);
            }

        }

        /// <summary>
        /// 删除投票活动  TODO 使用ttl删除，并处理相关事务逻辑
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("delete")]
        [AuthToken(Roles = "admin,teacher")]
        public async Task<IActionResult> Delete(JsonElement request)
        {
            try
            {
                var (userid, _, _,school) = HttpContext.GetAuthTokenInfo();
                if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
                if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
                var client = _azureCosmos.GetCosmosClient();
                
                Vote vote =await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Vote>(id.GetString(), new PartitionKey($"{code}") );
                bool flag = false;
                //必须是本人或者这个学校的管理者才能删除
                if (vote.creatorId == userid)
                {
                    flag = true;
                }
                else {
                    if (vote.scope == "school"&& vote.school.Equals(school)) {
                        flag = true;
                    }
                }
                if (flag)
                {
                    //使用ttl删除，并处理相关事务逻辑
                    vote.ttl = 1;
                    vote.status = 404;
                    vote = await client.GetContainer("TEAMModelOS", "Common").UpsertItemAsync(vote,  new PartitionKey($"{vote.code}"));
                    await _dingDing.SendBotMsg($"{_option.Location}-投票活动【{vote.name}-{vote.id}-ttl={vote.ttl}】正在操作", GroupNames.成都开发測試群組);
                    _azureRedis.GetRedisClient(8).KeyDelete($"Vote:Record:{vote.id}");
                    _azureRedis.GetRedisClient(8).KeyDelete($"Vote:Count:{vote.id}");
                    await _dingDing.SendBotMsg($"{_option.Location}-投票活动【{vote.name}-{vote.id}】被删除", GroupNames.成都开发測試群組);

                    //删除blob 相关资料
                    await _azureStorage.GetBlobServiceClient().DelectBlobs(code.ToString(), $"vote/{id}");
                    //通知删除信息
                    var messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "delete", root = $"vote/{id}", name = $"{code}" }.ToJsonString());
                    messageBlob.ApplicationProperties.Add("name", "BlobRoot");
                    var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
                    await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageBlob);

                    return Ok(new { flag });
                }
                else {
                    return Ok(new { flag });
                }
            }
            catch (Exception e)
            {
                return BadRequest(e.StackTrace);
            }
        }


        /// <summary>
        /// 投票记录 当活动没结算且没有BlobUrl时则调用此接口
        /// </summary>
        /// <redis>
        /// 投票活动选项计数器 使用SortedSet（有序集合）ZSET 数据集合 使用命令 ZINCRBY  key:"Vote:Count:AAA",value:"A",score:1
        /// 投票活动 投票记录  使用Hash（哈希表）使用命令 key:"Vote:Record:AAA",feild:15283771540-20210105,value:"{"opt":["A","C","A"],"time":1608274766154}"
        /// </redis>
        /// <param name="request">
        /// !"id":"aaaa"
        /// !"code":"Vote-hbcn"/"code":"Vote-1606285227"
        /// </param>
        /// <returns>
        /// </returns>
        [ProducesDefaultResponseType]
        [HttpPost("record")]
        [AuthToken(Roles = "teacher,admin,student")]
        public async Task<IActionResult> Record(JsonElement request)
        {
            if (!request.TryGetProperty("id", out JsonElement id))
            {
                return BadRequest();
            }
            //活动分区
            if (!request.TryGetProperty("code", out JsonElement code))
            {
                return BadRequest();
            }
            //获取投票活动的所有投票记录
            var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Vote:Record:{id}");
            //获取投票活动的选项及投票数
            var counts = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Vote:Count:{id}");
            List<dynamic> options = new List<dynamic>();
            if (counts != null && counts.Length > 0)
            {
                foreach (var count in counts)
                {
                    options.Add(new   { code = count.Element.ToString(), count = (int)count.Score });
                }
            }
            List<JsonElement> res = new List<JsonElement>();
            foreach (var rcd in records)
            {
                var value = rcd.Value.ToString().ToObject<JsonElement>();
                res.Add(value);
            }
            return Ok(new { options, records= res});
        }

        /// <summary>
        /// 个人已投票记录查询
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("decided")]
        [AuthToken(Roles = "teacher,student")]
        public async Task<IActionResult> Decided(JsonElement request)
        {
            var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
            if (!request.TryGetProperty("id", out JsonElement id))
            {
                return BadRequest();
            }
            //活动分区
            if (!request.TryGetProperty("code", out JsonElement code))
            {
                return BadRequest();
            }
            //获取投票活动的所有投票记录
            var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Vote:Record:{id}:{userid}");
            List<JsonElement> res = new List<JsonElement>();
            foreach (var rcd in records)
            {
                var value = rcd.Value.ToString().ToObject<JsonElement>();
                res.Add(value);
            }
            return Ok(new { records= res });
        }


        /// <summary>
        /// 投票
        /// </summary>
        /// <redis>
        /// 投票活动选项计数器 使用SortedSet（有序集合）ZSET 数据集合 使用命令 ZINCRBY  key:"Vote:Count:AAA",value:"A",score:1
        /// 投票活动 投票记录  使用Hash（哈希表）使用命令 key:"Vote:Record:AAA",feild:15283771540-20210105,value:"{"opt":["A","C","A"],"time":1608274766154}"
        /// </redis>
        /// <param name="request">
        /// !"id":"aaaa"
        /// !"code":"Vote-hbcn"/"code":"Vote-1606285227"
        /// !"option":{"A":5,"B":6}/{"1":5,"2":8}
        /// </param>
        /// <returns>
        /// msgid=0投票失败，1投票成功，2不在时间范围内，3不在发布范围内，4投票周期内重复投票，5周期内的可投票数不足
        /// 
        /// </returns>
        [ProducesDefaultResponseType]
        [HttpPost("decide")]
        [AuthToken(Roles = "teacher,student")]
        public async Task<IActionResult> Decide(JsonElement request)
        {
            var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
            int msgid = await ActivityStudentService.Decide(request, _azureCosmos, _azureRedis, userid);
            return Ok(new { msgid });
        }
        /// <summary>
        /// 投票
        /// </summary>
        /// <redis>
        /// 投票活动选项计数器 使用SortedSet（有序集合）ZSET 数据集合 使用命令 ZINCRBY  key:"Vote:Count:AAA",value:"A",score:1
        /// 投票活动 投票记录  使用Hash（哈希表）使用命令 key:"Vote:Record:AAA",feild:15283771540-20210105,value:"{"opt":["A","C","A"],"time":1608274766154}"
        /// </redis>
        /// <param name="request">
        /// !"id":"aaaa"
        /// !"code":"Vote-hbcn"/"code":"Vote-1606285227"
        /// !"option":{"A":5,"B":6}/{"1":5,"2":8}
        /// !"userid":"15283771540"
        /// </param>
        /// <returns>
        /// msgid=0投票失败，1投票成功，2不在时间范围内，3不在发布范围内，4投票周期内重复投票，5周期内的可投票数不足,6未设置投票项
        /// </returns>
        [ProducesDefaultResponseType]
        [HttpPost("decide-mock")]
        public async Task<IActionResult> DecideMock(JsonElement request)
        {
            //var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
            //活动id
            if (request.TryGetProperty("userid", out JsonElement userid))
            {
                int msgid = await ActivityStudentService.Decide(request, _azureCosmos, _azureRedis, $"{userid}");
                return Ok(new { msgid });
            }
            else { return Ok(new { msgid = 0 }); }
        }
    }
}