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.DI;
using TEAMModelOS.SDK.DI.AzureCosmos.Inner;
using TEAMModelOS.SDK.Extension;
using TEAMModelOS.SDK;
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 System.IO;
using System.Dynamic;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Sas;
using Lib.AspNetCore.ServerSentEvents;
using TEAMModelFunction;
using TEAMModelOS.SDK.Models.Cosmos.Common;
using HTEXLib.COMM.Helpers;

namespace TEAMModelOS.Controllers.Core
{
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    //[Authorize(Roles = "HiTool")]
    [Route("hiscan")]
    [ApiController]
    public class HiScanController : 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 ServerSentEventsService _sse;
        public HiScanController(AzureCosmosFactory azureCosmos, AzureServiceBusFactory serviceBus, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option,
           AzureRedisFactory azureRedis, AzureStorageFactory azureStorage//, ServerSentEventsService sse
                                                                         )
        {
            _azureCosmos = azureCosmos;
            _serviceBus = serviceBus;
            _snowflakeId = snowflakeId;
            _dingDing = dingDing;
            _option = option?.Value;
            _azureRedis = azureRedis;
            _azureStorage = azureStorage;
            //_sse = sse;
        }

        ///<summary>
        ///查询教师的阅卷任务列表
        /// </summary>
        /// <data>
        ///    ! "code":"tmdid"
        /// </data>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("get-schoolinfo")]
        // [AuthToken(Roles = "teacher,admin")]
        public async Task<IActionResult> GetSchoolinfo(JsonElement request)
        {
            List<dynamic> schools = new List<dynamic>();
            if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
            var client = _azureCosmos.GetCosmosClient();
            var response = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync($"{id}", new PartitionKey("Base"));
            if (response.Status == 200)
            {
                var json = await JsonDocument.ParseAsync(response.ContentStream);
                string name = $"{json.RootElement.GetProperty("name")}";
                string picture = $"{json.RootElement.GetProperty("picture")}";
                if (json.RootElement.TryGetProperty("schools", out JsonElement value))
                {
                    foreach (var obj in value.EnumerateArray())
                    {
                        string statusNow = obj.GetProperty("status").ToString();
                        //正式加入才会有
                        if (statusNow.Equals("join"))
                        {
                            //dynamic schoolExtobj = new ExpandoObject();
                            var schoolJson = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync($"{obj.GetProperty("schoolId")}", new PartitionKey("Base"));
                            var school = await JsonDocument.ParseAsync(schoolJson.ContentStream);
                            var schoolId = obj.GetProperty("schoolId");
                            var schoolName = obj.GetProperty("name");
                            var schoolPicture = school.RootElement.GetProperty("picture");
                            //检查学校购买的模组是否包含阅卷模组,暂不检查
                            //int count = 0;
                            //string sql = $" SELECT value(count(product))  FROM c join product in c.service.product      where c.id ='{schoolId}'  and  c.pk='Product'  and product.prodCode='YMPCVCIM' ";
                            //await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<int>(sql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Product") }))
                            //{
                            //    count = item;
                            //}
                            //if (count > 0)
                            //{
                            //    schools.Add(new { name = $"{schoolName}", picture = $"{schoolPicture}", id = $"{schoolId}" });
                            //}
                            schools.Add(new { name = $"{schoolName}", picture = $"{schoolPicture}", id = $"{schoolId}" });
                        }
                    }
                }
                var (tblob_uri, tblob_sas) = _azureStorage.GetBlobContainerSAS($"{id}", BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete);
                return Ok(new { schools, teacher = new { name, picture, id, bloburl = tblob_uri, blobsas = tblob_sas } });
            }
            else
            {
                return BadRequest();
            }

        }
        ///<summary>
        ///查询教师的阅卷任务列表
        /// </summary>
        /// <data>
        ///    ! "code":"tmdid"
        /// </data>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("get-examinfo")]
        // [AuthToken(Roles = "teacher,admin")]
        public async Task<IActionResult> GetExaminfo(JsonElement request)
        {
            try
            {
                List<SheetConfig> configs = new List<SheetConfig>();
                HashSet<string> classesSet = new HashSet<string>();

                List<ExamRcd> sexamRcds = new List<ExamRcd>();

                List<ExamRcd> psexamRcds = new List<ExamRcd>();
                List<ExamRcd> ppexamRcds = new List<ExamRcd>();
                List<ExamRcd> pexamRcds = new List<ExamRcd>();
                if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
                if (!request.TryGetProperty("schoolId", out JsonElement _schoolId)) return BadRequest();
                var client = _azureCosmos.GetCosmosClient();
                School school = null;
                try
                {
                    school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{_schoolId}", new PartitionKey("Base"));
                }
                catch (CosmosException ex)
                {
                    if (ex.Status == 404)
                    {
                        school = null;
                    }
                }
                var response = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync($"{id}", new PartitionKey("Base"));
                if (school != null)
                {
                    //检查学校购买的模组是否包含阅卷模组
                    int count = 0;
                    string sql = $" SELECT value(count(product))  FROM c join product in c.service.product      where c.id ='{_schoolId}'  and  c.pk='Product'  and product.prodCode='YMPCVCIM' ";
                    await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<int>(sql, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Product") }))
                    {
                        count = item;
                    }
                    if (count > 0)
                    {
                        //获取学校线下阅卷评测
                        sexamRcds = await GetExam("school", $"{_schoolId}", $"{_schoolId}", client, configs, classesSet);
                    }
                    if (response.Status == 200)
                    {
                        //获取scope=school
                        psexamRcds = await GetExam("school", $"{_schoolId}", $"{id}", client, configs, classesSet);
                        if (psexamRcds.IsNotEmpty())
                        {
                            pexamRcds.AddRange(psexamRcds);
                        }
                    }

                }
                if (response.Status == 200)
                {
                    //获取scope=private
                    ppexamRcds = await GetExam("private", null, $"{id}", client, configs, classesSet);
                    if (ppexamRcds.IsNotEmpty())
                    {
                        pexamRcds.AddRange(ppexamRcds);
                    }
                }
                (List<TmdInfo> tmdids, List<StuInfo> students, List<ClassListInfo> classInfo) = await TriggerStuActivity.GetStuList(client, _dingDing, classesSet.ToList(), $"{_schoolId}");
                List<SheetConfig> configsN = new List<SheetConfig>();
                foreach (var config in configs)
                {
                    if (config.scope.Equals("school"))
                    {
                        try
                        {
                            SheetConfig con = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<SheetConfig>(config.id, new PartitionKey(config.code));
                            configsN.Add(con);
                        }
                        catch (CosmosException ex) { }
                    }
                    else
                    {
                        try
                        {
                            SheetConfig con = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<SheetConfig>(config.id, new PartitionKey(config.code));
                            configsN.Add(con);
                        }
                        catch (CosmosException ex) { }
                    }
                }
                //处理学校发布的评测
                if (sexamRcds.IsNotEmpty())
                {
                    sexamRcds.SelectMany(y => y.classes).ToList().ForEach(z => {
                        var a = classInfo.Where(m => m.id.Equals(z.id)).FirstOrDefault();
                        if (a != null)
                        {
                            z.name = a.name;
                            z.stuInfos = a.stuInfos;
                            z.tmdInfos = a.tmdInfos;
                        }
                    });
                    sexamRcds.SelectMany(y => y.papers).ToList().ForEach(z => {
                        if (z.sheet != null)
                        {
                            var a = configsN.Where(m => m.id == z.sheet.id).FirstOrDefault();
                            if (a != null)
                            {
                                z.sheet = a;
                            }
                        }
                    });
                }

                //处理教师发布的个人班级评测和学校班级评测
                if (pexamRcds.IsNotEmpty())
                {
                    pexamRcds.SelectMany(y => y.classes).ToList().ForEach(z => {
                        var a = classInfo.Where(m => m.id == z.id).FirstOrDefault();
                        if (a != null)
                        {
                            z.name = a.name;
                            z.stuInfos = a.stuInfos;
                            z.tmdInfos = a.tmdInfos;
                        }
                    });
                    pexamRcds.SelectMany(y => y.papers).ToList().ForEach(z => {
                        if (z.sheet != null)
                        {
                            var a = configsN.Where(m => m.id == z.sheet.id).FirstOrDefault();
                            if (a != null)
                            {
                                z.sheet = a;
                            }
                        }
                    });
                }
                string teacherBlobSas = null;
                string teacherBlobUrl = null;
                string schoolBlobSas = null;
                string schoolBlobUrl = null;
                if (ppexamRcds.IsNotEmpty())
                {
                    var (tblob_uri, tblob_sas) = _azureStorage.GetBlobContainerSAS($"{id}", BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
                    teacherBlobUrl = tblob_uri;
                    teacherBlobSas = tblob_sas;
                }
                if (psexamRcds.IsNotEmpty() || sexamRcds.IsNotEmpty())
                {
                    var (sblob_uri, sblob_sas) = _azureStorage.GetBlobContainerSAS(school.id, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Write);
                    schoolBlobUrl = sblob_uri;
                    schoolBlobSas = sblob_sas;
                }
                return Ok(new { teacherBlobSas, teacherBlobUrl, schoolBlobSas, schoolBlobUrl, school = sexamRcds.IsNotEmpty() ? sexamRcds : null, teacher = pexamRcds.IsNotEmpty() ? pexamRcds : null });

            }
            catch (Exception ex)
            {
                await _dingDing.SendBotMsg($"IES5，{_option.Location}，hiscan/verify-qrcode()\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
                return BadRequest();
            }
        }
        private async Task<List<ExamRcd>> GetExam(string scope, string school, string code, CosmosClient client, List<SheetConfig> sheet, HashSet<string> classesSet)
        {
            List<ExamRcd> examRcds = new List<ExamRcd>();
            int i = 1;
            StringBuilder sql = new StringBuilder($"SELECT  * FROM c  where   c.progress='going' and c.scope='{scope}' ");
            if (!string.IsNullOrEmpty(school))
            {
                sql.Append($"  and c.school='{school}' ");
            }
            //await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<Correct>(queryText: "SELECT  * FROM c where c.source='2' and c.progress='going' order by c.createTime  ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Correct-{code}") }))
            await foreach (var exam in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<ExamInfo>(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{code}") }))
            {
                List<ClassListInfo> classes = new List<ClassListInfo>();
                if (exam.classes.IsNotEmpty())
                {
                    exam.classes.ForEach(x => { classes.Add(new ClassListInfo { id = x }); classesSet.Add(x); });
                }
                if (exam.stuLists.IsNotEmpty())
                {
                    exam.stuLists.ForEach(x => { classes.Add(new ClassListInfo { id = x }); classesSet.Add(x); });
                }
                List<PaperRcd> dys = new List<PaperRcd>();
                foreach (var pap in exam.papers)
                {
                    if (!string.IsNullOrEmpty(pap.sheet))
                    {
                        if (exam.scope.Equals("school"))
                        {
                            SheetConfig config = new SheetConfig { id = pap.sheet, no = pap.sheetNo, scope = exam.scope, code = $"SheetConfig-{exam.school}" };
                            dys.Add(new PaperRcd { name = pap.name, answers = pap.answers, point = pap.point, sheet = config });
                            sheet.Add(config);
                        }
                        else
                        {
                            SheetConfig config = new SheetConfig { id = pap.sheet, no = pap.sheetNo, scope = exam.scope, code = $"SheetConfig-{code}" };
                            dys.Add(new PaperRcd { name = pap.name, answers = pap.answers, point = pap.point, sheet = config });
                            sheet.Add(config);
                        }
                    }
                    else
                    {
                        dys.Add(new PaperRcd { name = pap.name, answers = pap.answers, point = pap.point, sheet = null });
                    }
                }
                examRcds.Add(new ExamRcd
                {
                    id = exam.id,
                    name = exam.name,
                    startTime = exam.startTime,
                    endTime = exam.endTime,
                    period = exam.period,
                    grades = exam.grades,
                    subjects = exam.subjects,
                    papers = dys,
                    classes = classes,
                    scope = exam.scope
                });
            }
            return examRcds;
        }



        ///<summary>
        ///查询教师的阅卷任务列表
        /// </summary>
        /// <data>
        ///    ! "code":"tmdid"
        /// </data>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("get-exam-by-sheet")]
        // [AuthToken(Roles = "teacher,admin")]
        public async Task<IActionResult> GetExamBySheet(JsonElement request)
        {
            try
            {
                HashSet<string> classesSet = new HashSet<string>();
                ExamData examData = null;
                if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
                if (!request.TryGetProperty("schoolId", out JsonElement _schoolId)) return BadRequest();
                if (!request.TryGetProperty("sheetNo", out JsonElement _sheetNo)) return BadRequest();
                if (!request.TryGetProperty("scope", out JsonElement _scope)) return BadRequest();
                var client = _azureCosmos.GetCosmosClient();
                School school = null;
                try
                {
                    school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{_schoolId}", new PartitionKey("Base"));
                }
                catch (CosmosException ex)
                {
                    if (ex.Status == 404)
                    {
                        school = null;
                    }
                }
                var response = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync($"{id}", new PartitionKey("Base"));
               
                if ($"{_scope}".Equals("school", StringComparison.OrdinalIgnoreCase))
                {
                    examData = await GetExamBySheet("school", $"{_schoolId}", $"{_schoolId}", client,  classesSet, $"{_sheetNo}");
                    if (response.Status == 200 && examData == null)
                    {
                        //获取scope=school
                        examData = await GetExamBySheet("school", $"{_schoolId}", $"{id}", client,  classesSet, $"{_sheetNo}");
                    }
                }
                else {
                    //获取scope=private
                    examData = await GetExamBySheet("private", null, $"{id}", client,  classesSet, $"{_sheetNo}");
                }
              
                (List<TmdInfo> tmdids, List<StuInfo> students, List<ClassListInfo> classInfo) = await TriggerStuActivity.GetStuList(client, _dingDing, classesSet.ToList(), $"{_schoolId}");
                List<SheetConfig> configsN = new List<SheetConfig>();
                if (examData.sheet != null) {
                    if (examData.sheet.scope.Equals("school"))
                    {
                        try
                        {
                            SheetConfig con = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<SheetConfig>(examData.sheet.id, new PartitionKey(examData.sheet.code));
                            configsN.Add(con);
                        }
                        catch (CosmosException ex) { }
                    }
                    else
                    {
                        try
                        {
                            SheetConfig con = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<SheetConfig>(examData.sheet.id, new PartitionKey(examData.sheet.code));
                            configsN.Add(con);
                        }
                        catch (CosmosException ex) { }
                    }
                }
                if (examData != null)
                {
                    examData.classes.ForEach(z => {
                        var a = classInfo.Where(m => m.id.Equals(z.id)).FirstOrDefault();
                        if (a != null)
                        {
                            z.name = a.name;
                            z.stuInfos = a.stuInfos;
                            z.tmdInfos = a.tmdInfos;
                        }
                    });
                    if (examData.sheet!=null) {
                        var a = configsN.Where(m => m.id == examData.sheet.id && m.scope.Equals(examData.sheet.scope)).FirstOrDefault();
                        if (a != null)
                        {
                            examData.sheet = a;
                        }
                    }
                }
              
                string blobSas = null;
                string blobUrl = null;
                ExamData exam = null;
                if ($"{_scope}".Equals("school", StringComparison.OrdinalIgnoreCase))
                {
                    if (examData != null)
                    {
                        var (sblob_uri, sblob_sas) = _azureStorage.GetBlobContainerSAS(school.id, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Write);
                        blobUrl = sblob_uri;
                        blobSas = sblob_sas;
                        exam = examData;
                    }
                }
                else {
                    if (examData != null)
                    {
                        var (tblob_uri, tblob_sas) = _azureStorage.GetBlobContainerSAS($"{id}", BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List);
                        blobUrl = tblob_uri;
                        blobSas = tblob_sas;
                        exam = examData;
                    }
                }
                return Ok(new { blobUrl, blobSas, exam});

            }
            catch (Exception ex)
            {
                await _dingDing.SendBotMsg($"IES5，{_option.Location}，get-exam-by-sheet\n{ex.Message}{ex.StackTrace}{request.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
                return BadRequest();
            }
        }

        private async Task<ExamData> GetExamBySheet(string scope, string school, string code, CosmosClient client,HashSet<string> classesSet, string sheetNo)
        {
            ExamData examRcds = null;
            int i = 1;
            StringBuilder sql = new StringBuilder($"SELECT  value(c) FROM c  join papers in c.papers where c.scope='{scope}' and papers.sheetNo='{sheetNo}' ");
            if (!string.IsNullOrEmpty(school))
            {
                sql.Append($"  and c.school='{school}' ");
            }
            //await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<Correct>(queryText: "SELECT  * FROM c where c.source='2' and c.progress='going' order by c.createTime  ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Correct-{code}") }))
            await foreach (var exam in client.GetContainer(Constant.TEAMModelOS, "Common").GetItemQueryIterator<ExamInfo>(queryText: sql.ToString(), requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Exam-{code}") }))
            {
                List<ClassListInfo> classes = new List<ClassListInfo>();
                if (exam.classes.IsNotEmpty())
                {
                    exam.classes.ForEach(x => { classes.Add(new ClassListInfo { id = x }); classesSet.Add(x); });
                }
                if (exam.stuLists.IsNotEmpty())
                {
                    exam.stuLists.ForEach(x => { classes.Add(new ClassListInfo { id = x }); classesSet.Add(x); });
                }

                PaperRcdData paper = null;
                ExamSubjectData subjectData = null;
                PaperSimple pap = exam.papers.Find(x => x.sheetNo == sheetNo);
                if (pap != null) {
                    int index = exam.papers.FindIndex(x => x.sheetNo == sheetNo);
                    ExamSubject subject = exam.subjects[index];
                    subjectData = new ExamSubjectData { id = subject.id, name = subject.name };
                }
                SheetConfig config = null;
                if (!string.IsNullOrEmpty(pap.sheet))
                {
                    if (exam.scope.Equals("school"))
                    {
                        config = new SheetConfig { id = pap.sheet, scope = exam.scope, code = $"SheetConfig-{exam.school}" };
                        paper=new PaperRcdData { name = pap.name, answers = pap.answers, point = pap.point };
                    }
                    else
                    {
                        config = new SheetConfig { id = pap.sheet, scope = exam.scope, code = $"SheetConfig-{code}" };
                        paper = new PaperRcdData { name = pap.name, answers = pap.answers, point = pap.point };
                    }
                }
                else
                {
                    paper = new PaperRcdData { name = pap.name, answers = pap.answers, point = pap.point, };
                }
                examRcds = new ExamData
                {
                    id = exam.id,
                    name = exam.name,
                    startTime = exam.startTime,
                    endTime = exam.endTime,
                    period = exam.period,
                    grades = exam.grades,
                    subject = subjectData,
                    paper = paper,
                    classes = classes,
                    scope = exam.scope,
                    sheet = config
                };
            }
            return examRcds;
        }


    }
    public record PaperRcdData
    {
        public string name { get; set; }
        public List<List<string>> answers { get; set; } = new List<List<string>>();
        public List<double> point { get; set; } = new List<double>();

    }
    public record PaperRcd
    {
        public string name { get; set; }
        public List<List<string>> answers { get; set; } = new List<List<string>>();
        public List<double> point { get; set; } = new List<double>();
        public SheetConfig sheet { get; set; }

    }
    public class ExamSubjectData
    {
        public string id { get; set; }
        public string name { get; set; }
    }
    public record ExamData
    {
        public SheetConfig sheet { get; set; }
        public string id { get; set; }
        public string name { get; set; }
        public long startTime { get; set; }
        public long endTime { get; set; }
        public PeriodSimple period { get; set; }
        public List<Grade> grades { get; set; }
        public ExamSubjectData subject { get; set; }
        public PaperRcdData paper { get; set; }
        public List<ClassListInfo> classes { get; set; }
        public string scope { get; set; }
    }
    public record ExamRcd
    {
        public string id { get; set; }
        public string name { get; set; }
        public long startTime { get; set; }
        public long endTime { get; set; }
        public PeriodSimple period { get; set; }
        public List<Grade> grades { get; set; }
        public List<ExamSubject> subjects { get; set; }
        public List<PaperRcd> papers { get; set; }
        public List<ClassListInfo> classes { get; set; }
        public string scope { get; set; }
    }
}
