using Azure.Cosmos;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
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.Models;
using Microsoft.Extensions.Options;
using TEAMModelOS.Filter;
using TEAMModelOS.Services.Common;
using Azure.Storage.Blobs.Models;
using TEAMModelOS.SDK.Models.Cosmos.Common.Inner;
using TEAMModelOS.SDK.Module.AzureBlob.Configuration;
using System.Net.Http;
using TEAMModelOS.SDK.Models.Cosmos;
using Azure.Messaging.ServiceBus;
using Azure.Storage.Sas;
using TEAMModelOS.SDK.Models.Cosmos.Common;
using Microsoft.Extensions.Configuration;

namespace TEAMModelOS.Controllers
{
    /// <summary>
    /// 投票活动
    /// </summary>
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    //[Authorize(Roles = "IES5")]
    [Route("common/survey")]
    [ApiController]
    public class SurveyController : 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;
        private readonly IHttpClientFactory _clientFactory;
        public IConfiguration _configuration { get; set; }
        public SurveyController(AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option, 
            AzureRedisFactory azureRedis, AzureStorageFactory azureStorage, IHttpClientFactory clientFactory,IConfiguration configuration)
        {
            _snowflakeId= snowflakeId;
            _serviceBus = serviceBus;
            _azureCosmos = azureCosmos;
            _dingDing = dingDing;
            _option = option?.Value;
            _azureRedis = azureRedis;
            _azureStorage = azureStorage;
            _clientFactory = clientFactory;
            _configuration = configuration;
        }


        /// <summary>
        /// 新增 或 修改投票活动
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("upsert")]
        [AuthToken(Roles = "teacher,admin")]
        public async Task<IActionResult> Upsert(Survey request) {
            try {
                var client = _azureCosmos.GetCosmosClient();
                request.code = request.pk + "-" + request.code;
                long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                request.createTime = now;
                request.ttl = -1;               
                //如果设置的时间是小于当前时间则立即发布
                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($"survey/{request.id}");
                        messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "insert", root = $"survey/{request.id}", name = $"{request.school}" }.ToJsonString());
                    }
                    else
                    {
                        request.size = await _azureStorage.GetBlobContainerClient(request.creatorId).GetBlobsSize($"survey/{request.id}");
                        messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "insert", root = $"survey/{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($"survey/{request.id}");
                        messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "update", root = $"survey/{request.id}", name = $"{request.school}" }.ToJsonString());
                    }
                    else
                    {
                        request.size = await _azureStorage.GetBlobContainerClient(request.creatorId).GetBlobsSize($"survey/{request.id}");
                        messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "update", root = $"survey/{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<Survey>();
                        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 { survey = request});
            } catch (Exception ex) {
                await _dingDing.SendBotMsg($"OS，{_option.Location}，common/survey/save()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
                return BadRequest(ex.StackTrace);
            }
           
        }
        /// <summary>
        /// 查询问卷调查,用于列表，编辑，查看
        /// </summary>
        /// <data>
        ///Survey-学校/教师编码  活动分区        !"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.ValueKind.Equals(JsonValueKind.Null)  && stime.TryGetInt64(out long data))
                    {
                        stimestamp = data;
                    };
                };
                //默认当前时间
                var etimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                if (requert.TryGetProperty("etime", out JsonElement etime))
                {
                    if (!etime.ValueKind.Equals(JsonValueKind.Null)&&!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.ValueKind.Equals(JsonValueKind.Null) && 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> surveys = new List<object>();
                var client = _azureCosmos.GetCosmosClient();
                var query = $"select c.id,c.name,c.code,c.startTime,c.endTime,c.progress,c.classes 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($"Survey-{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())
                        {
                            surveys.Add(obj.ToObject<JsonElement>());
                        }
                        //如果需要分页则跳出
                        if (iscontinuation)
                        {
                            continuationToken = item.GetContinuationToken();
                            break;
                        }
                    }
                }
                return Ok(new { surveys, continuationToken });
            } catch (Exception ex) {
                await _dingDing.SendBotMsg($"OS，{_option.Location}，common/survey/find()\n{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
                return BadRequest(ex.StackTrace);
            }
          
        }
        ///<summary>
        /// 查询问卷调查,用于创建者列表，编辑，查看，作答人员查看
        /// </summary>
        /// <data>
        ///    ! "id":"3c075347-75ef-4bcb-ae03-68678d02d5ef",
        ///    ! "code":"Survey-hbcn"/"code":"Survey-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();
                Survey survey = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Survey>(id.GetString(), new PartitionKey($"{code}"));
                if (survey != null)
                {

                    return Ok(new { survey });
                }
                else
                {
                    return BadRequest("id,code不存在！");
                }
            }
            catch (Exception ex)
            {
                await _dingDing.SendBotMsg($"OS，{_option.Location}，common/survey/find-id()\n{ex.Message}{requert.ToJsonString()}", 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();

                Survey survey = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Survey>(id.GetString(), new PartitionKey($"{code}"));
                bool flag = false;
                //必须是本人或者这个学校的管理者才能删除
                if (survey.creatorId == userid)
                {
                    flag = true;
                }
                else
                {
                    if (survey.scope == "school" && survey.school.Equals(school))
                    {
                        flag = true;
                    }
                }
                if (flag)
                {
                    //使用ttl删除，并处理相关事务逻辑
                    survey.ttl = 1;
                    survey.status = 404;
                    survey = await client.GetContainer("TEAMModelOS", "Common").UpsertItemAsync(survey, new PartitionKey($"{survey.code}"));
                    _azureRedis.GetRedisClient(8).KeyDelete($"Survey:Record:{survey.id}");
                    _azureRedis.GetRedisClient(8).KeyDelete($"Survey:Submit:{survey.id}");
                    //删除blob 相关资料
                    await _azureStorage.GetBlobServiceClient().DelectBlobs(code.ToString(), $"survey/{id}");
                    //通知删除信息
                    var messageBlob = new ServiceBusMessage(new { id = Guid.NewGuid().ToString(), progress = "delete", root = $"survey/{id}", name = $"{code}" }.ToJsonString());
                    messageBlob.ApplicationProperties.Add("name", "BlobRoot");
                    var ActiveTask = _configuration.GetValue<string>("Azure:ServiceBus:ActiveTask");
                    await _serviceBus.GetServiceBusClient().SendMessageAsync(ActiveTask, messageBlob);
                    await _dingDing.SendBotMsg($"{_option.Location}-问卷调查【{survey.name}-{survey.id}】被删除", GroupNames.成都开发測試群組);
                    return Ok(new { flag });
                }
                else
                {
                    return Ok(new { flag });
                }
            }
            catch (Exception e)
            {
                return BadRequest(e.StackTrace);
            }
        }

        /// <summary>
        /// 问卷答案提交
        /// </summary>
        /// <redis>
        /// Survey:Record:e6b887f8-adb5-3677-bcc7-3b36450909df_Survey-1595321354 {"C":2,"A":2,"other":2}
        /// </redis>
        /// <param name="request">
        /// !"id":"aaaa"
        /// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
        /// !"record":[["A","B"],["A"],["D"],[],["建议提升服务质量"]]
        /// </param>
        /// <returns>
        /// msgid=0投票失败，1提交成功，2不在时间范围内，3不在发布范围内，6未设置投票项
        /// </returns>
        [ProducesDefaultResponseType]
        [HttpPost("answer")]
        [AuthToken(Roles = "teacher,student")]
        public async Task<IActionResult> Answer(JsonElement request)
        {
            //  var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
            if (request.TryGetProperty("userid", out JsonElement userid)) {
                int msgid = await ActivityStudentService.Answer(request, _azureCosmos, _azureRedis, $"{userid}", _azureStorage);
                return Ok(new { msgid });
            }
            else { return Ok(new { msgid = 0 }); }
        }


        /// <summary>
        /// 问卷答案提交
        /// </summary>
        /// <redis>
        /// Survey:Record:e6b887f8-adb5-3677-bcc7-3b36450909df_Survey-1595321354 {"C":2,"A":2,"other":2}
        /// </redis>
        /// <param name="request">
        /// !"id":"aaaa"
        /// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
        /// </param>
        /// <returns>
        /// msgid=0投票失败，1提交成功，2不在时间范围内，3不在发布范围内，6未设置投票项
        /// </returns>
        [ProducesDefaultResponseType]
        [HttpPost("answered-list")]
        [AuthToken(Roles = "teacher,student")]
        public async Task<IActionResult> AnsweredList(JsonElement request)
        {
            //  var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
            if (!request.TryGetProperty("id", out JsonElement id))
            {
                return BadRequest();
            }
            //活动分区
            if (!request.TryGetProperty("code", out JsonElement code))
            {
                return BadRequest();
            }
            List<string> userids = new List<string>();
            var values= await _azureRedis.GetRedisClient(8).SetMembersAsync($"Survey:Submit:{id}");
            if (values != default && values.Length>0) {
                foreach(var val in values) {
                    userids.Add(val);
                }
            }
            return Ok(new { userids = userids }); 
            
        }

        /// <summary>
        /// 问卷答案提交
        /// </summary>
        /// <redis>
        /// Survey:Record:e6b887f8-adb5-3677-bcc7-3b36450909df_Survey-1595321354 {"C":2,"A":2,"other":2}
        /// </redis>
        /// <param name="request">
        /// !"id":"aaaa"
        /// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
        /// </param>
        /// <returns>
        /// msgid=0投票失败，1提交成功，2不在时间范围内，3不在发布范围内，6未设置投票项
        /// </returns>
        [ProducesDefaultResponseType]
        [HttpPost("answered")]
        [AuthToken(Roles = "teacher,student")]
        public async Task<IActionResult> Answered(JsonElement request)
        {
             var (userid, _, _, _) = HttpContext.GetAuthTokenInfo();
            if (!request.TryGetProperty("id", out JsonElement id))
            {
                return BadRequest();
            }
            //活动分区
            if (!request.TryGetProperty("code", out JsonElement code))
            {
                return BadRequest();
            }
            List<string> userids = new List<string>();
            var answered = await _azureRedis.GetRedisClient(8).SetContainsAsync($"Survey:Submit:{id}",userid);
            
            return Ok(new { answered = answered });

        }


        /// <summary>
        /// 问卷记录 当活动没结算且没有BlobUrl时则调用此接口
        /// </summary>
        /// <redis>
        /// {"C":2,"A":2,"other":2}
        /// </redis>
        /// <param name="request">
        /// !"id":"aaaa"
        /// !"code":"Survey-hbcn"/"code":"Survey-1606285227"
        /// </param>
        /// <returns>
        /// </returns>
        [ProducesDefaultResponseType]
        [HttpPost("record")]
        [AuthToken(Roles = "admin,teacher,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($"Survey:Record:{id}");
            List<dynamic> res = new List<dynamic>();
            foreach (var rcd in records)
            {
                var value = rcd.Value.ToString().ToObject<JsonElement>();
                res.Add(new { index = rcd.Name.ToString(), ans = value }) ;
            }
            return Ok(new {records = res});
        }


    }
    public class QuestionRecord
    {
        public int index { get; set; }
        public Dictionary<string, HashSet<string>> opt { get; set; } = new Dictionary<string, HashSet<string>>();
        public Dictionary<string, string> other { get; set; } = new Dictionary<string, string>();
    }
}