using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using TEAMModelOS.Models;
using TEAMModelOS.SDK;
using TEAMModelOS.SDK.DI;
using System.Text.Json;
using TEAMModelOS.SDK.Models;
using TEAMModelOS.SDK.Extension;
using Azure.Cosmos;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using System.IO;
using System.Dynamic;
using TEAMModelOS.SDK.Context.Configuration;
using System.Net.Http;
using System.Net;
using Newtonsoft.Json;
using System.Linq;
using StackExchange.Redis;

namespace TEAMModelOS.Controllers
{
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    //[Authorize(Roles = "IES5")]
    [Route("school/init")]
    [ApiController]
    public class SchoolController : ControllerBase
    {

        public AzureCosmosFactory _azureCosmos;
        private readonly AzureStorageFactory _azureStorage;
        private readonly AzureRedisFactory _azureRedis;
        private readonly DingDing _dingDing;
        private readonly Option _option;
        int baseSpaceSize = 1; //學校保底空間大小(1G)
        private readonly double bytes = 1073741824;
        private readonly int redisAclassoneDbNum = 8; //AclassOne Redis DB號

        public SchoolController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, DingDing dingDing, IOptionsSnapshot<Option> option)
        {
            _azureCosmos = azureCosmos;
            _azureStorage = azureStorage;
            _azureRedis = azureRedis;
            _dingDing = dingDing;
            _option = option?.Value;
        }
        /// <summary>
        /// 保存或更新学校
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        //[AuthToken(Roles = "admin")]
        [HttpPost("upsert")]
        public async Task<IActionResult> Upsert(TEAMModelOS.SDK.Models.School requert)
        {
            var (_, _, _, school) = HttpContext.GetAuthTokenInfo();
            try
            {
                TEAMModelOS.SDK.Models.School schoolInfo = new TEAMModelOS.SDK.Models.School();
                var client = _azureCosmos.GetCosmosClient();
                var schoolContainer = client.GetContainer("TEAMModelOS", "School");
                var response = await schoolContainer.ReadItemStreamAsync(requert.id, new PartitionKey($"Base"));
                if (response.Status == 200)
                {
                    schoolInfo = await schoolContainer.UpsertItemAsync(requert, new PartitionKey($"Base"));
                }
                else
                {
                    requert.code = "Base";
                    schoolInfo = await schoolContainer.CreateItemAsync(requert, new PartitionKey($"Base"));
                }
                return Ok(new { schoolInfo });
            }
            catch (Exception ex)
            {
                await _dingDing.SendBotMsg($"CoreAPI2，{_option.Location}，school/upsert()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
                return BadRequest();
            }
            /*ResponseBuilder builder = ResponseBuilder.custom();
            if (string.IsNullOrEmpty(request.id))
            {
                List<School> schools = await _azureCosmos.FindByDict<School>(new Dictionary<string, object> { { "id", request.schoolCode } });
                if (schools.IsNotEmpty())
                {
                    //return builder.Error(ResponseCode.DATA_EXIST, "学校已存在！").build();
                    return Ok(new { V = "学校已经存在！" });
                }
				request.code = "Base";
				//request.id = request.schoolCode;
			}
            else {
                *//*if (request.id.Equals(request.schoolCode))
                {*//*
                    School datas = await _azureCosmos.SaveOrUpdate<School>(request);
                    return Ok(new{ datas});
                *//*}
                else
                {
                    //return builder.Error(ResponseCode.PARAMS_ERROR, "id,schoolCode必须相同！").build();
                    return Ok(new { V = "id,schoolCode必须相同！" });
                }*/
            /*List<School> schools = await _azureCosmos.FindByDict<School>(new Dictionary<string, object> { { "id", request.id } });
            if (schools.IsEmpty())
            {
                return builder.Error(ResponseCode.PARAMS_ERROR, "id不存在，不能更新").build();
            }*//*
        }
        return Ok();*/
        }
        /// <summary>
        /// 查找学校
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        //[AuthToken(Roles = "teacher")]
        [HttpPost("find")]
        public async Task<IActionResult> Find(JsonElement requert)
        {
            if (!requert.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
            var client = _azureCosmos.GetCosmosClient();
            List<TEAMModelOS.SDK.Models.School> schools = new List<TEAMModelOS.SDK.Models.School>();
            var query = $"select c.id,c.pk,c.code, c.name,c.region,c.province,c.city,c.timeZone,c.picture,c.size,c.period,c.campuses from c where c.id ='{school_code}'";
            await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Base") }))
            {
                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())
                    {
                        schools.Add(obj.ToObject<TEAMModelOS.SDK.Models.School>());
                    }
                }
            }

            return Ok(new { schools });
            /* ResponseBuilder builder = ResponseBuilder.custom();

             if (request.TryGetProperty("code", out JsonElement code) &&! string.IsNullOrEmpty(code.ToString()))
             {
                 List<School> sc = await _azureCosmos.FindByDict<School>(request);
                 return builder.Data(sc).build();
             }
             else {
                 return builder.Data(null).build();
             }*/
        }
        /// <summary>
        /// 取得所有學校(只取基本資料)
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("get-all-school-base")]
        public async Task<IActionResult> GetAllSchoolBaesInfo(JsonElement request)
        {
            var client = _azureCosmos.GetCosmosClient();
            List<object> schools = new List<object>();
            await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: $"SELECT c.id, c.code, c.name, c.region, c.province, c.city, c.address, c.picture FROM c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
            {
                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())
                    {
                        schools.Add(obj.ToObject<object>());
                    }
                }
            }
            return Ok(new { schools });
        }

        /// <summary>
        /// 取得某學校基本資料 
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("get-school-base")]
        public async Task<IActionResult> GetSchoolBaesInfo(JsonElement request)
        {
            if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();

            var client = _azureCosmos.GetCosmosClient();
            var schoolContainer = client.GetContainer("TEAMModelOS", "School");
            //取得學校學制、年級、教室
            List<object> classes = new List<object>();
            await foreach (var item in schoolContainer.GetItemQueryStreamIterator(queryText: $"SELECT c.id, c.name, c.gradeId FROM c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Class-{school_code}") }))
            {
                var jsonc = await JsonDocument.ParseAsync(item.ContentStream);
                foreach (var classeinfo in jsonc.RootElement.GetProperty("Documents").EnumerateArray())
                {
                    dynamic classExtobj = new ExpandoObject();
                    classExtobj.id = classeinfo.GetProperty("id");
                    classExtobj.name = classeinfo.GetProperty("name");
                    classExtobj.gradeId = classeinfo.GetProperty("gradeId");
                    classes.Add(classExtobj);
                }
            }
            List<object> periods = new List<object>();
            List<object> grades = new List<object>();
            var responsesch = await schoolContainer.ReadItemStreamAsync(school_code.ToString(), new PartitionKey($"Base"));
            if (responsesch.Status == 200)
            {
                var jsons = await JsonDocument.ParseAsync(responsesch.ContentStream);
                if (jsons.RootElement.TryGetProperty("period", out JsonElement periodJobj))
                {
                    foreach (var periodinfo in periodJobj.EnumerateArray())
                    {
                        dynamic periodExtobj = new ExpandoObject();
                        periodExtobj.id = periodinfo.GetProperty("id");
                        periodExtobj.name = periodinfo.GetProperty("name");
                        periods.Add(periodExtobj);
                        if (periodinfo.TryGetProperty("grades", out JsonElement gradesJobj))
                        {
                            foreach (var gradeinfo in gradesJobj.EnumerateArray())
                            {
                                dynamic gradeExtobj = new ExpandoObject();
                                gradeExtobj.id = gradeinfo.GetProperty("id");
                                gradeExtobj.name = gradeinfo.GetProperty("name");
                                gradeExtobj.periodId = periodinfo.GetProperty("id");
                                grades.Add(gradeExtobj);
                            }
                        }
                    }
                }
            }
            return Ok(new { periods, grades, classes });
        }

        /// <summary>
        /// 取得某學校產品資料 
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("get-school-product")]
        public async Task<IActionResult> GetSchoolProductInfo(JsonElement request)
        {
            if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
            var clientContainer = _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "School");

            List<deviceBoundRich> serialDeviceUpdList = new List<deviceBoundRich>(); //要更新DB的序號內容
            List<SerialInfoBaseWithdeviceBoundExt> serial = new List<SerialInfoBaseWithdeviceBoundExt>(); //最後要輸出的序號結果
            List<object> service = new List<object>();
            List<object> hard = new List<object>();
            List<deviceForCoreService> uuidList = new List<deviceForCoreService>(); //要向CoreService詢問deviceID及硬體資訊的UUID列表
            var response = await clientContainer.ReadItemStreamAsync(school_code.ToString(), new PartitionKey("Product"));
            if (response.Status == 200)
            {
                var json = await JsonDocument.ParseAsync(response.ContentStream);
                //軟體
                if (json.RootElement.TryGetProperty("serial", out JsonElement serialJobj))
                {
                    foreach (var serialInfo in serialJobj.EnumerateArray())
                    {
                        serial.Add(serialInfo.ToObject<SerialInfoBaseWithdeviceBoundExt>());
                        if (serialInfo.TryGetProperty("deviceBound", out JsonElement deviceBoundJobj) && !string.IsNullOrWhiteSpace(deviceBoundJobj.ToString()))
                        {
                            foreach (var deviceBoundRow in deviceBoundJobj.EnumerateArray())
                            {
                                deviceForCoreService uuidForCore = new deviceForCoreService();
                                uuidForCore.sn = (!string.IsNullOrWhiteSpace(Convert.ToString(serialInfo.GetProperty("serial")))) ? Convert.ToString(serialInfo.GetProperty("serial")) : null;
                                uuidForCore.uuid1 = (!string.IsNullOrWhiteSpace(Convert.ToString(deviceBoundRow.GetProperty("uuid")))) ? Convert.ToString(deviceBoundRow.GetProperty("uuid")) : null;
                                uuidForCore.uuid2 = (!string.IsNullOrWhiteSpace(Convert.ToString(deviceBoundRow.GetProperty("uuid2")))) ? Convert.ToString(deviceBoundRow.GetProperty("uuid2")) : null;
                                uuidForCore.device_id = (!string.IsNullOrWhiteSpace(Convert.ToString(deviceBoundRow.GetProperty("deviceId")))) ? Convert.ToString(deviceBoundRow.GetProperty("deviceId")) : null;
                                uuidForCore.class_id = (!string.IsNullOrWhiteSpace(Convert.ToString(deviceBoundRow.GetProperty("classId")))) ? Convert.ToString(deviceBoundRow.GetProperty("classId")) : null;
                                uuidList.Add(uuidForCore);
                            }
                        }
                    }
                }
                //取得DeviceInfo From Core
                List<deviceFromCoreService> coreUuidList = (List<deviceFromCoreService>)GetDeviceFromCoreAsync(uuidList).GetAwaiter().GetResult();
                foreach (SerialInfoBaseWithdeviceBoundExt serialRow in serial)
                {
                    var deviceBoundArray = new List<deviceBoundExt>();
                    List<deviceFromCoreService> coreUuid = coreUuidList
                           .Where((deviceFromCoreService x) => x.sn == serialRow.serial)
                           .ToList();
                    foreach (deviceFromCoreService deviceRow in coreUuid)
                    {
                        //前端顯示用
                        deviceForCoreService deviceBoundRow = uuidList.Where(u => u.sn == deviceRow.sn && u.uuid1 == deviceRow.uuid1 && u.uuid2 == deviceRow.uuid2).FirstOrDefault();
                        deviceBoundExt deviceBoundExt = new deviceBoundExt();
                        deviceBoundExt.uuid = deviceBoundRow.uuid1;
                        deviceBoundExt.uuid2 = deviceBoundRow.uuid2;
                        deviceBoundExt.classId = deviceBoundRow.class_id;
                        deviceBoundExt.deviceId = deviceRow.device_id;
                        deviceBoundExt.os = deviceRow.os;
                        deviceBoundExt.ip = deviceRow.local_ip;
                        deviceBoundExt.cpu = deviceRow.cpu;
                        deviceBoundExt.pcname = deviceRow.pc_name;
                        deviceBoundExt.osver = deviceRow.os_ver;
                        deviceBoundArray.Add(deviceBoundExt);
                        //DB更新用
                        deviceBound serialDeviceBoundRow = serialRow.deviceBound.Where(d => d.uuid == deviceBoundRow.uuid1 && d.uuid2 == deviceBoundRow.uuid2).FirstOrDefault();
                        if (serialDeviceBoundRow.deviceId != deviceRow.device_id)
                        {
                            deviceBoundRich deviceBoundUpdRow = new deviceBoundRich();
                            deviceBoundUpdRow.serial = deviceRow.sn;
                            deviceBoundUpdRow.uuid = deviceBoundRow.uuid1;
                            deviceBoundUpdRow.uuid2 = deviceBoundRow.uuid2;
                            deviceBoundUpdRow.classId = deviceBoundRow.class_id;
                            deviceBoundUpdRow.deviceId = deviceRow.device_id;
                            serialDeviceUpdList.Add(deviceBoundUpdRow);
                        }
                    }
                    serialRow.deviceBound = deviceBoundArray;
                }

                //服務
                if (json.RootElement.TryGetProperty("service", out JsonElement serviceJobj))
                {
                    //取得active的主週期、所有主週期歷史
                    List<ServiceMainPeriod> activeMainPeriod = new List<ServiceMainPeriod>();
                    List<ServiceMainPeriod> historyMainPeriod = new List<ServiceMainPeriod>();
                    //ServiceMainPeriod activeMainPeriod = new ServiceMainPeriod();
                    if (serviceJobj.TryGetProperty("mainperiod", out JsonElement mainperiodJobj))
                    {
                        foreach (var mainperiodRow in mainperiodJobj.EnumerateArray())
                        {
                            historyMainPeriod.Add(mainperiodRow.ToObject<ServiceMainPeriod>());
                            if (mainperiodRow.GetProperty("active").GetBoolean())
                            {
                                activeMainPeriod.Add(mainperiodRow.ToObject<ServiceMainPeriod>());
                            }
                        }
                    }

                    //取得active主週期的副週期
                    List<ServicePeriod> activePeriodOfMain = new List<ServicePeriod>();
                    List<ServicePeriod> historyPeriodOfMain = new List<ServicePeriod>();
                    if (serviceJobj.TryGetProperty("period", out JsonElement periodJobj))
                    {
                        foreach (var periodRow in periodJobj.EnumerateArray())
                        {
                            historyPeriodOfMain.Add(periodRow.ToObject<ServicePeriod>());
                            foreach (ServiceMainPeriod mainPeriodRow in activeMainPeriod)
                            {
                                if (periodRow.GetProperty("mainPeriodId").ToString() == mainPeriodRow.mainPeriodId)
                                {
                                    activePeriodOfMain.Add(periodRow.ToObject<ServicePeriod>());
                                }
                            }
                        }
                    }
                    //計算各產品時間區域
                    bool buySpaceFlg = false;
                    ////取得學校空間使用狀況
                    var blobClient = _azureStorage.GetBlobContainerClient(school_code.ToString());
                    long? docSize = await blobClient.GetBlobsSize("doc");
                    long? videoSize = await blobClient.GetBlobsSize("video");
                    long? imageSize = await blobClient.GetBlobsSize("image");
                    long? paperSize = await blobClient.GetBlobsSize("paper");
                    long? itemSize = await blobClient.GetBlobsSize("item");
                    long? otherSize = await blobClient.GetBlobsSize("other");
                    long? studentSize = await blobClient.GetBlobsSize("student");
                    long teacherSize = 0;
                    if (serviceJobj.TryGetProperty("product", out JsonElement serviceProductJobj))
                    {

                        foreach (var serviceProductRow in serviceProductJobj.EnumerateArray())
                        {
                            ServiceProductResult serviceProductResultRow = CalServiceProductAuth(activeMainPeriod, activePeriodOfMain, serviceProductRow.ToObject<ServiceProduct>());
                            if (!string.IsNullOrWhiteSpace(serviceProductResultRow.prodCode))
                            {
                                switch (serviceProductResultRow.prodCode)
                                {
                                    case "RYGVCPLY": //AClassOne買斷、週期
                                    case "AEGMCPLY":
                                        ServiceProductAclassoneResult serviceProductAclassoneResult = new ServiceProductAclassoneResult();
                                        serviceProductAclassoneResult.prodCode = serviceProductResultRow.prodCode;
                                        serviceProductAclassoneResult.noperiod = serviceProductResultRow.noperiod;
                                        serviceProductAclassoneResult.serviceType = serviceProductResultRow.serviceType;
                                        serviceProductAclassoneResult.startDate = serviceProductResultRow.startDate;
                                        serviceProductAclassoneResult.endDate = serviceProductResultRow.endDate;
                                        serviceProductAclassoneResult.avaliable = serviceProductResultRow.avaliable;
                                        serviceProductAclassoneResult.staUsed = 0;
                                        serviceProductAclassoneResult.dynUsed = 0;
                                        if (json.RootElement.TryGetProperty("aclassone", out JsonElement aclassoneJobj) && aclassoneJobj.ValueKind != JsonValueKind.Null)
                                        {
                                            int total = (aclassoneJobj.TryGetProperty("total", out JsonElement totalJobj)) ? totalJobj.GetInt32() : 0;
                                            serviceProductAclassoneResult.staUsed = (aclassoneJobj.TryGetProperty("used", out JsonElement usedJobj)) ? usedJobj.GetInt32() : 0; //固定分配數
                                            List<string> dyncIdList = GetSchoolDynamicAclassOneIDList(school_code.GetString()); //動態使用ID
                                            serviceProductAclassoneResult.dynUsed = dyncIdList.Count;
                                        }
                                        service.Add(serviceProductAclassoneResult);
                                        break;
                                    case "IPALYEIY": //智慧教學服務空間
                                        ////取得目前使用狀況
                                        //取得教師分配空間
                                        var query = $"SELECT SUM(c.size) as size FROM c";
                                        await foreach (var item in clientContainer.GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school_code}") }))
                                        {
                                            var jsonts = await JsonDocument.ParseAsync(item.ContentStream);
                                            foreach (var obj in jsonts.RootElement.GetProperty("Documents").EnumerateArray())
                                            {
                                                teacherSize = obj.GetProperty("size").GetInt64() * 1073741824;//G換算成bytes
                                            }
                                        }
                                        //欄位取得
                                        dynamic serviceSpaceProductInfo = new ExpandoObject();
                                        serviceSpaceProductInfo.prodCode = serviceProductResultRow.prodCode;
                                        serviceSpaceProductInfo.noperiod = serviceProductResultRow.noperiod;
                                        serviceSpaceProductInfo.serviceType = serviceProductResultRow.serviceType;
                                        serviceSpaceProductInfo.startDate = serviceProductResultRow.startDate;
                                        serviceSpaceProductInfo.endDate = serviceProductResultRow.endDate;
                                        serviceSpaceProductInfo.avaliable = (long)(serviceProductResultRow.avaliable + this.baseSpaceSize) * 1073741824; //G換算成bytes
                                        serviceSpaceProductInfo.doc = docSize;
                                        serviceSpaceProductInfo.video = videoSize;
                                        serviceSpaceProductInfo.image = imageSize;
                                        serviceSpaceProductInfo.paper = paperSize;
                                        serviceSpaceProductInfo.item = itemSize;
                                        serviceSpaceProductInfo.other = otherSize;
                                        serviceSpaceProductInfo.student = studentSize;
                                        serviceSpaceProductInfo.teacher = teacherSize;
                                        serviceSpaceProductInfo.history = CalServiceProductOrderHistory(historyMainPeriod, historyPeriodOfMain, serviceProductRow.ToObject<ServiceProduct>()); ////購買紀錄
                                        service.Add(serviceSpaceProductInfo);
                                        buySpaceFlg = true;
                                        break;
                                    default:
                                        service.Add(serviceProductResultRow);
                                        break;
                                }
                            }
                        }
                    }
                    //學校保底空間追加
                    if (!buySpaceFlg) //未購買任何空間
                    {
                        dynamic serviceSpaceProductInfo = new ExpandoObject();
                        serviceSpaceProductInfo.prodCode = "IPALYEIY";
                        serviceSpaceProductInfo.noperiod = false;
                        serviceSpaceProductInfo.serviceType = "space";
                        serviceSpaceProductInfo.startDate = 0;
                        serviceSpaceProductInfo.endDate = 0;
                        serviceSpaceProductInfo.avaliable = this.baseSpaceSize * 1073741824; //1G換算成bytes
                        serviceSpaceProductInfo.doc = docSize;
                        serviceSpaceProductInfo.video = videoSize;
                        serviceSpaceProductInfo.image = imageSize;
                        serviceSpaceProductInfo.paper = paperSize;
                        serviceSpaceProductInfo.item = itemSize;
                        serviceSpaceProductInfo.other = otherSize;
                        serviceSpaceProductInfo.student = studentSize;
                        serviceSpaceProductInfo.teacher = teacherSize;
                        serviceSpaceProductInfo.history = null;
                        service.Add(serviceSpaceProductInfo);
                    }
                }

                //硬體
                if (json.RootElement.TryGetProperty("hard", out JsonElement hardJobj) && hardJobj.ValueKind != JsonValueKind.Null)
                {
                    hard.Add(hardJobj.ToObject<object>());
                }

                //更新DB
                if (serialDeviceUpdList.Count > 0)
                {
                    SchoolProduct schoolProductItem = json.ToObject<SchoolProduct>();
                    foreach (deviceBoundRich serialDeviceUpdRow in serialDeviceUpdList)
                    {
                        SerialInfoBaseWithdeviceBound updSerialInfo = schoolProductItem.serial.Where(s => s.serial == serialDeviceUpdRow.serial).FirstOrDefault();
                        deviceBound updDeviceBound = updSerialInfo.deviceBound.Where(d => d.uuid == serialDeviceUpdRow.uuid && d.uuid2 == serialDeviceUpdRow.uuid2).FirstOrDefault();
                        updDeviceBound.deviceId = serialDeviceUpdRow.deviceId;
                    }
                    await clientContainer.ReplaceItemAsync<SchoolProduct>(schoolProductItem, schoolProductItem.id, new PartitionKey("Product"));
                }

            }

            return Ok(new { serial, service, hard });
        }

        /// <summary>
        /// 取得CoreDevice資訊
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private async Task<List<deviceFromCoreService>> GetDeviceFromCoreAsync(List<deviceForCoreService> uuidList)
        {
            List<deviceFromCoreService> result = new List<deviceFromCoreService>();
            try
            {
                string url = BaseConfigModel.Configuration["HaBookAuth:CoreService:deviceinfo"];
                HttpClient client = new HttpClient();
                var content = new StringContent(JsonConvert.SerializeObject(uuidList), Encoding.UTF8, "application/json");
                HttpResponseMessage responseMessage = await client.PostAsync(url, content);
                if (responseMessage.StatusCode == HttpStatusCode.OK)
                {
                    string responseBody = responseMessage.Content.ReadAsStringAsync().Result;
                    result = System.Text.Json.JsonSerializer.Deserialize<List<deviceFromCoreService>>(responseBody.ToString());
                }
                return result;
            }
            catch (Exception ex)
            {
                return result;
            }
        }

        /// <summary>
        /// 計算各產品的初始結束時間及可用數
        /// </summary>
        /// <param name="mainPeriodList">active的主周期</param>
        /// <param name="periodList">附屬周期</param>
        /// <param name="serviceProduct">產品資訊</param>
        /// <returns></returns>
        private ServiceProductResult CalServiceProductAuth(List<ServiceMainPeriod> mainPeriodList, List<ServicePeriod> periodList, ServiceProduct serviceProduct)
        {
            periodZone periodZoneResult = new periodZone();
            List<periodZone> periodZone = new List<periodZone>();
            //篩選出產品有的副週期
            List<string> existPeriodIdList = new List<string>();
            if (serviceProduct.auth.Count > 0)
            {
                foreach (ServiceProductAuth serviceProductAuthRow in serviceProduct.auth)
                {
                    if (!string.IsNullOrWhiteSpace(serviceProductAuthRow.periodId) && !existPeriodIdList.Contains(serviceProductAuthRow.periodId))
                    {
                        existPeriodIdList.Add(serviceProductAuthRow.periodId);
                    }
                }
            }
            List<ServicePeriod> periodOrder = periodList.Where(p => existPeriodIdList.Contains(p.periodId)).OrderBy(p => Int32.Parse(p.periodId)).ToList();

            //combine period
            if (periodOrder.Count() > 0)
            {

                //篩選出主週期(複數active主週期對策) ※最終篩出唯一一組 篩選原則：(1)由此產品有的副週期ID篩出 (2)若還有複數筆，則期間長者勝出
                List<string> existMainPeriodIdList = new List<string>();
                foreach (ServicePeriod periodRow in periodOrder)
                {
                    if (!existMainPeriodIdList.Contains(periodRow.mainPeriodId))
                    {
                        existMainPeriodIdList.Add(periodRow.mainPeriodId);
                    }
                }
                ServiceMainPeriod mainPeriod = mainPeriodList.Where(w => existMainPeriodIdList.Contains(w.mainPeriodId)).OrderByDescending(w => w.endDate - w.startDate).First();
                List<ServicePeriod> periods = periodOrder.Where(p => p.mainPeriodId == mainPeriod.mainPeriodId).ToList();

                //combine period，compare to mainPeriod start, end
                periodZone = combinePeriodZone(periods);
                periodZoneResult.startDate = (periodZone[0].startDate > mainPeriod.startDate) ? periodZone[0].startDate : mainPeriod.startDate;
                periodZoneResult.endDate = (periodZone[0].endDate < mainPeriod.endDate) ? periodZone[0].endDate : mainPeriod.endDate;
            }

            //return
            ServiceProductResult serviceProductResult = new ServiceProductResult();
            if ((serviceProduct.noperiod && periodZoneResult.startDate == 0 && periodZoneResult.endDate == 0) || (!serviceProduct.noperiod && periodZoneResult.startDate > 0 && periodZoneResult.endDate > 0))
            {
                serviceProductResult.prodCode = serviceProduct.prodCode;
                serviceProductResult.noperiod = serviceProduct.noperiod;
                serviceProductResult.serviceType = serviceProduct.serviceType;
                serviceProductResult.startDate = periodZoneResult.startDate;
                serviceProductResult.endDate = periodZoneResult.endDate;
                serviceProductResult.avaliable = serviceProduct.avaliable;
            }

            return serviceProductResult;
        }

        /// <summary>
        /// 計算各產品的購買歷史紀錄
        /// </summary>
        /// <param name="mainPeriodList">所有的主周期</param>
        /// <param name="periodList">所有附屬周期</param>
        /// <param name="serviceProduct">產品資訊</param>
        /// <returns></returns>
        private List<ServiceProductAuthHistoryStartEnd> CalServiceProductOrderHistory(List<ServiceMainPeriod> mainPeriodList, List<ServicePeriod> periodList, ServiceProduct serviceProduct)
        {
            List<ServiceProductAuthHistoryStartEnd> serviceProductOrderStartEndList = new List<ServiceProductAuthHistoryStartEnd>();

            //GROUP BY orderId
            if (serviceProduct.auth.Count > 0)
            {
                List<ServiceProductAuthHistory> serviceProductOrderList = new List<ServiceProductAuthHistory>();
                foreach (ServiceProductAuth serviceProductAuthRow in serviceProduct.auth)
                {
                    ServiceProductAuthHistory existServiceProductAuthHistory = serviceProductOrderList.Where(a => a.orderId == serviceProductAuthRow.orderId).FirstOrDefault();
                    if (existServiceProductAuthHistory != null)
                    {
                        if (!existServiceProductAuthHistory.periodIdList.Contains(serviceProductAuthRow.periodId))
                        {
                            existServiceProductAuthHistory.periodIdList.Add(serviceProductAuthRow.periodId);
                        }
                    }
                    else
                    {
                        ServiceProductAuthHistory serviceProductAuthHistoryRow = new ServiceProductAuthHistory();
                        serviceProductAuthHistoryRow.orderId = serviceProductAuthRow.orderId;
                        int y = Int32.Parse(serviceProductAuthRow.orderId.Substring(0, 4));
                        int m = Int32.Parse(serviceProductAuthRow.orderId.Substring(4, 2));
                        int d = Int32.Parse(serviceProductAuthRow.orderId.Substring(6, 2));
                        serviceProductAuthHistoryRow.orderDate = new DateTimeOffset(y, m, d, 0, 0, 0, TimeSpan.Zero).ToUnixTimeSeconds();
                        serviceProductAuthHistoryRow.number = serviceProductAuthRow.number;
                        serviceProductAuthHistoryRow.unit = serviceProductAuthRow.unit;
                        serviceProductAuthHistoryRow.periodIdList = new List<string>();
                        serviceProductAuthHistoryRow.periodIdList.Add(serviceProductAuthRow.periodId);
                        serviceProductOrderList.Add(serviceProductAuthHistoryRow);
                    }
                }

                foreach (ServiceProductAuthHistory serviceProductOrderRow in serviceProductOrderList)
                {
                    ServiceProductAuthHistoryStartEnd ServiceProductAuthHistoryStartEndRow = new ServiceProductAuthHistoryStartEnd();
                    //combine period
                    List<ServicePeriod> periodOrder = periodList.Where((ServicePeriod x) => serviceProductOrderRow.periodIdList.Contains(x.periodId)).OrderBy(p => Int32.Parse(p.periodId)).ToList();
                    List<periodZone> periodZone = combinePeriodZone(periodOrder);
                    ServiceProductAuthHistoryStartEndRow.startDate = periodZone[0].startDate;
                    ServiceProductAuthHistoryStartEndRow.endDate = periodZone[0].endDate;
                    ServiceProductAuthHistoryStartEndRow.orderId = serviceProductOrderRow.orderId;
                    ServiceProductAuthHistoryStartEndRow.orderDate = serviceProductOrderRow.orderDate;
                    ServiceProductAuthHistoryStartEndRow.number = serviceProductOrderRow.number;
                    ServiceProductAuthHistoryStartEndRow.unit = serviceProductOrderRow.unit;
                    serviceProductOrderStartEndList.Add(ServiceProductAuthHistoryStartEndRow);
                }
            }
            //return
            return serviceProductOrderStartEndList;
        }

        //子週期合併開始結束時間
        private List<periodZone> combinePeriodZone(List<ServicePeriod> periods)
        {
            List<periodZone> periodZone = new List<periodZone>();
            foreach (ServicePeriod periodRow in periods)
            {
                if (periodZone.Count == 0)
                {
                    periodZone periodZoneNew = new periodZone();
                    periodZoneNew.startDate = periodRow.startDate;
                    periodZoneNew.endDate = periodRow.endDate;
                    periodZone.Add(periodZoneNew);
                }
                else
                {
                    bool zoneExistFlg = false;
                    for (int i = 0; i < periodZone.Count; i++) //考慮到副週期可能斷成數個block，整合後取第一個
                    {
                        if (periodRow.startDate <= periodZone[i].endDate + 10 && periodZone[i].endDate + 10 < periodRow.endDate)
                        {
                            periodZone[i].endDate = periodRow.endDate;
                            zoneExistFlg = true;
                        }
                        else if (periodZone[i].startDate <= periodRow.endDate + 10 && periodRow.endDate + 10 < periodZone[i].endDate)
                        {
                            periodZone[i].startDate = periodRow.startDate;
                            zoneExistFlg = true;
                        }
                    }
                    if (!zoneExistFlg)
                    {
                        periodZone periodZoneNew = new periodZone();
                        periodZoneNew.startDate = periodRow.startDate;
                        periodZoneNew.endDate = periodRow.endDate;
                        periodZone.Add(periodZoneNew);
                    }
                }
            }
            return periodZone;
        }

        /// <summary>
        /// 取得某學校AClassOne授權及使用資料 
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("get-school-aclassone")]
        public async Task<IActionResult> GetSchoolAclassoneInfo(JsonElement request)
        {
            if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();

            var clientContainer = _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "School");
            var response = await clientContainer.ReadItemStreamAsync(school_code.ToString(), new PartitionKey("Product"));
            int total = 0; //可分配總數
            int staNum = 0; //固定分配數
            int dyncNum = 0; //動態分配數
            List<string> staIds = new List<string>(); //固定分配學生ID列
            List<string> dyncIds = new List<string>(); //動態分配學生ID列
            if (response.Status == 200)
            {
                var json = await JsonDocument.ParseAsync(response.ContentStream);
                if (json.RootElement.TryGetProperty("service", out JsonElement serviceJobj))
                {
                    //取得active主週期
                    List<ServiceMainPeriod> activeMainPeriod = new List<ServiceMainPeriod>();
                    if (serviceJobj.TryGetProperty("mainperiod", out JsonElement mainperiodJobj))
                    {
                        foreach (var mainperiodRow in mainperiodJobj.EnumerateArray())
                        {
                            if (mainperiodRow.GetProperty("active").GetBoolean())
                            {
                                activeMainPeriod.Add(mainperiodRow.ToObject<ServiceMainPeriod>());
                            }
                        }
                    }
                    //取得active主週期的副週期
                    List<ServicePeriod> activePeriodOfMain = new List<ServicePeriod>();
                    if (serviceJobj.TryGetProperty("period", out JsonElement periodJobj))
                    {
                        foreach (var periodRow in periodJobj.EnumerateArray())
                        {
                            foreach (ServiceMainPeriod mainPeriodRow in activeMainPeriod)
                            {
                                if (periodRow.GetProperty("mainPeriodId").ToString() == mainPeriodRow.mainPeriodId)
                                {
                                    activePeriodOfMain.Add(periodRow.ToObject<ServicePeriod>());
                                }
                            }
                        }
                    }
                    //取得AClassOne可用數量
                    if (serviceJobj.TryGetProperty("product", out JsonElement serviceProductJobj))
                    {
                        foreach (var serviceProductRow in serviceProductJobj.EnumerateArray())
                        {
                            //AClassOne買斷、週期
                            string prodCode = serviceProductRow.GetProperty("prodCode").GetString();
                            if (prodCode == "RYGVCPLY" || prodCode == "AEGMCPLY")
                            {
                                ServiceProductResult serviceProductResultRow = CalServiceProductAuth(activeMainPeriod, activePeriodOfMain, serviceProductRow.ToObject<ServiceProduct>());
                                total += serviceProductResultRow.avaliable;
                            }
                        }
                    }
                    //取得AClassOne固定分配數、動態分配數、固定分配學生ID
                    if (json.RootElement.TryGetProperty("aclassone", out JsonElement aclassoneJobj))
                    {
                        if (aclassoneJobj.ValueKind != JsonValueKind.Null)
                        {
                            if (aclassoneJobj.TryGetProperty("ids", out JsonElement ids) && ids.ValueKind != JsonValueKind.Null)
                            {
                                staIds = System.Text.Json.JsonSerializer.Deserialize<List<string>>(ids.ToJsonString());
                                staNum = staIds.Count;
                            }
                        }
                        dyncIds = GetSchoolDynamicAclassOneIDList(school_code.GetString());
                        dyncNum = dyncIds.Count;
                    }
                }
            }

            return Ok(new { total, staNum, dyncNum, staIds, dyncIds });
        }

        /// <summary>
        /// 取得某學校AClassOne動態可使用數 
        /// </summary>
        public int GetSchoolDynamicAclassOne(string schoolCode)
        {
            try
            {
                int result = 0;
                string key = schoolCode + ":" + "AclassOne" + ":" + "dynamic";
                var redisClient = _azureRedis.GetRedisClient(redisAclassoneDbNum);
                var dyncount = redisClient.StringGet(key);
                if (redisClient.KeyExists(key))
                {
                    result = Int32.Parse(redisClient.StringGet(key));
                }
                return result;
            }
            catch (Exception ex)
            {
                return 0;
            }
        }
        /// <summary>
        /// 取得某學校AClassOne動態已取用的ID List 
        /// </summary>
        public List<string> GetSchoolDynamicAclassOneIDList(string schoolCode)
        {
            string key = schoolCode + ":" + "AclassOne" + ":" + "dynamicIds";
            var redisClient = _azureRedis.GetRedisClient(redisAclassoneDbNum);
            RedisValue[] redisResult = redisClient.SetMembers(key);
            List<string> result = Array.ConvertAll(redisResult, x => (string)x).ToList();
            return result;
        }

        public long GetSchoolDynamicAclassOneIDCount(string schoolCode)
        {
            string key = schoolCode + ":" + "AclassOne" + ":" + "dynamicIds";
            var redisClient = _azureRedis.GetRedisClient(redisAclassoneDbNum);
            long result = redisClient.SetLength(key);
            return result;
        }

        /// <summary>
        /// [測試用]放入某學校的AClassOne動態學生ID 
        /// </summary>
        [ProducesDefaultResponseType]
        [HttpPost("set-school-aclassone-dync")]
        public IActionResult SetSchoolAclassoneDync(JsonElement request)
        {
            if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
            request.TryGetProperty("student_id", out JsonElement student_id);
            var redisClient = _azureRedis.GetRedisClient(redisAclassoneDbNum);
            string key1 = school_code + ":" + "AclassOne" + ":" + "dynamicIds";
            RedisValue[] redisIdsOriginal = redisClient.SetMembers(key1);
            var resultIdsOriginal = Array.ConvertAll(redisIdsOriginal, x => (string)x).ToList();
            redisClient.SetAdd(key1, student_id.GetString());
            RedisValue[] redisIds = redisClient.SetMembers(key1);
            var resultIds = Array.ConvertAll(redisIds, x => (string)x).ToList();
            string key2 = school_code + ":" + "AclassOne" + ":" + "dynamic";
            if (resultIds.Count > resultIdsOriginal.Count)
            {
                redisClient.StringDecrement(key2, 1);
            }
            string resultCount = redisClient.StringGet(key2);
            return Ok(new { resultIds, resultCount });
        }

        /// <summary>
        /// 設定某學校AClassOne固定分配授權學生
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("set-school-aclasson-sta")]
        public async Task<IActionResult> SetSchoolAclassoneStatic(JsonElement request)
        {
            if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
            if (!request.TryGetProperty("student_ids", out JsonElement student_ids)) return BadRequest();
            try
            {
                List<string> studentIds = System.Text.Json.JsonSerializer.Deserialize<List<string>>(student_ids.ToJsonString()); //新的學生ID列

                /* ERROR CODE定義：
                 * 0: 無錯誤
                 * 1: AClassOne授權數不足或無AClassOne授權
                 */
                int status = 0;
                string err = "";
                var clientContainer = _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "School");
                var response = await clientContainer.ReadItemStreamAsync(school_code.ToString(), new PartitionKey("Product"));
                if (response.Status == 200)
                {
                    int total = 0; //(回傳值)可分配總數
                    int staNum = 0; //(回傳值)固定分配數
                    int dyncNum = 0; //(回傳值)動態分配數
                    List<string> staIds = new List<string>(); //(回傳值)固定學生ID列
                    List<string> dyncIds = new List<string>(); //(回傳值)動態學生ID列
                    using (Stream stream = response.ContentStream)
                    {
                        using (StreamReader streamReader = new StreamReader(stream))
                        {
                            string content = streamReader.ReadToEnd();
                            SchoolProduct schoolProduct = System.Text.Json.JsonSerializer.Deserialize<SchoolProduct>(content);
                            if (schoolProduct.aclassone != null) //有AClassOne產品授權，schoolProduct.aclassone不會為null
                            {
                                total = schoolProduct.aclassone.total;
                                List<string> studentIdsInDB = schoolProduct.aclassone.ids; //舊的學生ID列
                                int totalInDB = schoolProduct.aclassone.total;
                                //STEP1 驗證所給的ID數是否超過AClassOne總數
                                if (studentIds.Count > totalInDB)
                                {
                                    status = 1;
                                    err = "AclassOne numbers is not enouth.";
                                    return Ok(new { status, err });
                                }
                                //STEP2 將學生ID放入 School.Product.aclassone.ids，更新aclassone.used
                                staIds = schoolProduct.aclassone.ids = studentIds;
                                staNum = schoolProduct.aclassone.used = studentIds.Count;
                                ////Update
                                await clientContainer.ReplaceItemAsync<SchoolProduct>(schoolProduct, schoolProduct.id, new PartitionKey("Product"));
                                //STEP3更新Redis.hbcn:AclassOne:dynamic ※註：只更新動態ID可用數，不更動動態ID列表，所以若可用數為0，當天被動態分配到的學生仍可使用至今日0時才會被清掉
                                int dynamicAclassCount = totalInDB - studentIds.Count; //動態可使用數
                                dyncNum = (int)GetSchoolDynamicAclassOneIDCount(school_code.GetString()); //動態ID已使用數
                                var redisClient = _azureRedis.GetRedisClient(redisAclassoneDbNum);                        
                                string keys = school_code.GetString() + ":" + "AclassOne" + ":" + "dynamic";
                                int updDynAclassCount = (dynamicAclassCount - dyncNum > 0) ? dynamicAclassCount - dyncNum : 0;
                                redisClient.StringSet(keys, updDynAclassCount);
                                string keyd = school_code.GetString() + ":" + "AclassOne" + ":" + "dynamicIds";
                                RedisValue[] redisIds = redisClient.SetMembers(keyd);
                                dyncIds = Array.ConvertAll(redisIds, x => (string)x).ToList();

                                return Ok(new { status, err, total, staNum, dyncNum, staIds, dyncIds });
                            }
                            else
                            {
                                status = 1;
                                err = "AClassOne has no authorization.";
                                return Ok(new { status, err });
                            }
                        }
                    }
                }
                else
                {
                    return BadRequest();
                }
            }
            catch (Exception ex)
            {
                return BadRequest();
            }
        }

        /// <summary>
        /// 回收某學校AClassOne固定分配、動態分配授權學生
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("recall-school-aclasson")]
        public async Task<IActionResult> RecallSchoolAclassone(JsonElement request)
        {
            if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
            string action = "all"; //預設回收：固定及動態均回收  sta:回收固定 dync:回收動態
            if (request.TryGetProperty("mode", out JsonElement mode))
            {
                if(mode.GetString() == "sta" || mode.GetString() == "dync")
                {
                    action = mode.GetString();
                }
            }
            int status = 0;
            string err = "";
            var redisClient = _azureRedis.GetRedisClient(redisAclassoneDbNum);
            string keys = school_code.GetString() + ":" + "AclassOne" + ":" + "dynamic";
            string keyd = school_code.GetString() + ":" + "AclassOne" + ":" + "dynamicIds";
            var clientContainer = _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "School");
            var response = await clientContainer.ReadItemStreamAsync(school_code.ToString(), new PartitionKey("Product"));
            if (response.Status == 200)
            {
                int total = 0; //(回傳值)可分配總數
                int staNum = 0; //(回傳值)固定分配數
                int dyncNum = 0; //(回傳值)動態分配數
                List<string> staIds = new List<string>(); //(回傳值)固定學生ID列
                List<string> dyncIds = new List<string>(); //(回傳值)動態學生ID列
                using (Stream stream = response.ContentStream)
                {
                    using (StreamReader streamReader = new StreamReader(stream))
                    {
                        string content = streamReader.ReadToEnd();
                        SchoolProduct schoolProduct = System.Text.Json.JsonSerializer.Deserialize<SchoolProduct>(content);
                        if (schoolProduct.aclassone != null) //有AClassOne產品授權，schoolProduct.aclassone不會為null
                        {
                            total = schoolProduct.aclassone.total;
                            staNum = schoolProduct.aclassone.used;
                            staIds = schoolProduct.aclassone.ids;
                            dyncNum = (int)GetSchoolDynamicAclassOneIDCount(school_code.GetString());
                            dyncIds = GetSchoolDynamicAclassOneIDList(school_code.GetString());
                            switch (action)
                            {
                                case "sta":
                                    staIds = schoolProduct.aclassone.ids = new List<string>();
                                    staNum = schoolProduct.aclassone.used = 0;
                                    await clientContainer.ReplaceItemAsync<SchoolProduct>(schoolProduct, schoolProduct.id, new PartitionKey("Product"));
                                    int updDynAclassCount = (total - dyncNum > 0) ? total - dyncNum : 0;
                                    redisClient.StringSet(keys, updDynAclassCount);
                                    break;
                                case "dync": //動態回收
                                    dyncNum = 0;
                                    dyncIds = new List<string>();
                                    redisClient.StringSet(keys, total - staNum);
                                    redisClient.KeyDelete(keyd);
                                    break;
                                case "all": //全回收
                                    staIds = schoolProduct.aclassone.ids = new List<string>();
                                    staNum = schoolProduct.aclassone.used = 0;
                                    await clientContainer.ReplaceItemAsync<SchoolProduct>(schoolProduct, schoolProduct.id, new PartitionKey("Product"));
                                    dyncNum = 0;
                                    dyncIds = new List<string>();
                                    redisClient.StringSet(keys, total);
                                    redisClient.KeyDelete(keyd);
                                    break;
                            }
                            return Ok(new { status, err, total, staNum, dyncNum, staIds, dyncIds });
                        }
                        else
                        {
                            status = 1;
                            err = "AClassOne has no authorization.";
                            return Ok(new { status, err });
                        }
                    }
                }
            }
            else
            {
                return BadRequest();
            }
        }

        /// <summary>
        /// 教師空間
        /// </summary>
        [ProducesDefaultResponseType]
        [HttpPost("teacher-space")]
        public async Task<IActionResult> TeacherSpace(JsonElement request)
        {
            // 必要檢查
            if (!request.TryGetProperty("school_code", out JsonElement code)) return BadRequest();
            if (!request.TryGetProperty("action", out JsonElement type)) return BadRequest();

            try
            {
                // [變數宣告]
                string school_code = code.ToString(); // 學校簡碼
                string action = type.ToString();  // 功能分類
                string queryText = ""; // 統一sql文記憶體

                // response
                string status = "0";
                string err = "";
                List<string> errTeachers = new List<string>();

                //[學校空間]
                var blobClient = _azureStorage.GetBlobContainerClient(school_code.ToString());
                long? docSize = await blobClient.GetBlobsSize("doc");
                long? videoSize = await blobClient.GetBlobsSize("video");
                long? imageSize = await blobClient.GetBlobsSize("image");
                long? paperSize = await blobClient.GetBlobsSize("paper");
                long? itemSize = await blobClient.GetBlobsSize("item");
                long? otherSize = await blobClient.GetBlobsSize("other");
                long? studentSize = await blobClient.GetBlobsSize("student");
                int avaliable = this.baseSpaceSize; // (G) 目前學校申請空間總數
                int teacherSpace = 0; // 教師可設定的空間量(G)
                int usedSpace = 0;//已被使用的空間量(G)

                // 取得學校目前的總空間數(G)
                queryText = $"SELECT p.prodCode, p.avaliable FROM c JOIN p IN c.service.product WHERE c.id = '{school_code}' AND p.prodCode = 'IPALYEIY'";
                await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: queryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Product") }))
                {
                    using var jsoncm = await JsonDocument.ParseAsync(item.ContentStream);
                    if (jsoncm.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                    {
                        foreach (var obj in jsoncm.RootElement.GetProperty("Documents").EnumerateArray())
                        {
                            avaliable += obj.GetProperty("avaliable").GetInt32();
                        }

                        docSize = docSize != null ? docSize : 0;
                        videoSize = videoSize != null ? videoSize : 0;
                        imageSize = imageSize != null ? imageSize : 0;
                        paperSize = paperSize != null ? paperSize : 0;
                        itemSize = itemSize != null ? itemSize : 0;
                        otherSize = otherSize != null ? otherSize : 0;
                        studentSize = studentSize != null ? studentSize : 0;
                        usedSpace = Convert.ToInt32(Math.Ceiling((double)((docSize + videoSize + imageSize + paperSize + itemSize + otherSize + studentSize) / bytes)));
                        teacherSpace = avaliable - usedSpace;
                    }
                }

                switch (action)
                {
                    case "baseSpace": // 現在的教師空間
                        return Ok(new { 
                            status, 
                            avaliable = avaliable.ToString(),
                            usedSpace = usedSpace.ToString()
                        });
                    case "upd": // 修改教師空間
                        // [二次檢核]
                        if (!request.TryGetProperty("teachers", out JsonElement list)) return BadRequest();
                        if (list.GetArrayLength() == 0) return BadRequest();

                        // 教師設定總數
                        int setSpaceTotal = 0;

                        // 教師List
                        JsonElement.ArrayEnumerator teachers = request.GetProperty("teachers").EnumerateArray();
                        List<string> ids = new List<string>();
                        foreach (var obj in teachers) { 
                            ids.Add(obj.GetProperty("id").ToString());
                            setSpaceTotal += String.IsNullOrEmpty(obj.GetProperty("size").ToString()) ?  0 : Convert.ToInt32(obj.GetProperty("size").ToString());
                        }

                        // 檢核總數是否超過
                        if (setSpaceTotal > teacherSpace)
                        {
                            status = "1"; // 要設定的空間總數大於目前學校有的
                            err = $"設定總量({setSpaceTotal}G)超過目前空間({teacherSpace}G)";
                            return Ok(new { status, err });
                        }
                        
                        queryText = $"select * from c where c.id in ({string.Join(",", ids.Select(o => $"'{o}'"))})";

                        await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: queryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school_code}") }))
                        {
                            using var jsoncm = await JsonDocument.ParseAsync(item.ContentStream);
                            if (jsoncm.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0 && count.GetInt16() == list.GetArrayLength())
                            {

                                List<SchoolTeacher> teachersInschool = new List<SchoolTeacher>();
                                foreach (var obj in jsoncm.RootElement.GetProperty("Documents").EnumerateArray())
                                {
                                    teachersInschool.Add(obj.ToObject<SchoolTeacher>());
                                }

                                foreach (var obj in teachers)
                                {
                                    SchoolTeacher teacher = teachersInschool.Where(t => t.id == obj.GetProperty("id").ToString()).FirstOrDefault<SchoolTeacher>();
                                    int orgTeacherSize = teacher.size;
                                    teacher.size = Convert.ToInt32(obj.GetProperty("size").ToString());

                                    // 修改DB裡Teacher的size
                                    var response = await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Teacher").ReadItemStreamAsync(teacher.id, new PartitionKey("Base"));
                                    if (response.Status == 200)
                                    {
                                        var json = await JsonDocument.ParseAsync(response.ContentStream);

                                        //軟體
                                        Teacher teacherHimself = json.ToObject<Teacher>();
                                        teacherHimself.size = teacherHimself.size - orgTeacherSize + teacher.size;

                                        //最後一起修改
                                        await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Teacher>(teacherHimself, teacherHimself.id, new PartitionKey("Base"));
                                        await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "School").ReplaceItemAsync<SchoolTeacher>(teacher, obj.GetProperty("id").ToString(), new PartitionKey($"Teacher-{school_code}"));
                                    } 
                                    else
                                    {
                                        status = "3";
                                        err = "有老師不存在於 Teacher 的DB";
                                    }
                                }

                            }
                            else 
                            {
                                // 有不存在的的老師ID
                                status = "2";
                                err = "有不存在的的老師ID";

                                List<string> teachersInschool = new List<string>();
                                foreach (var obj in jsoncm.RootElement.GetProperty("Documents").EnumerateArray())
                                {
                                    teachersInschool.Add(obj.GetProperty("id").ToString());
                                }

                                // 差集處理
                                errTeachers = ids.Except(teachersInschool).ToList();
                            }
                        }
                        return Ok(new { status, err, errTeachers });
                    case "retract": // 收回教師空間
                        // [取得DB資料]
                        queryText = "select * from c ";
                        string record = "0";

                        await foreach (var item in _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: queryText, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school_code}") }))
                        {
                            using var jsoncm = await JsonDocument.ParseAsync(item.ContentStream);
                            if (jsoncm.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                            {
                                // 修改的筆數
                                record = count.ToString();
                                List<SchoolTeacher> teachersInschool = new List<SchoolTeacher>();
                                foreach (var obj in jsoncm.RootElement.GetProperty("Documents").EnumerateArray())
                                {
                                    teachersInschool.Add(obj.ToObject<SchoolTeacher>());
                                }

                                foreach (SchoolTeacher teacher in teachersInschool)
                                {
                                    // 修改DB裡School的老師size
                                    int teacherSizeInSchool = teacher.size;
                                    teacher.size = 0;
                                    

                                    // 修改DB裡Teacher的size
                                    var response = await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Teacher").ReadItemStreamAsync(teacher.id, new PartitionKey("Base"));
                                    if (response.Status == 200) 
                                    {
                                        var json = await JsonDocument.ParseAsync(response.ContentStream);

                                        //軟體
                                        Teacher teacherHimself = json.ToObject<Teacher>();
                                        teacherHimself.size -= teacherSizeInSchool;

                                        // 最後一起修改
                                        await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "School").ReplaceItemAsync<SchoolTeacher>(teacher, teacher.id, new PartitionKey($"Teacher-{school_code}"));
                                        await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Teacher>(teacherHimself, teacherHimself.id, new PartitionKey("Base"));
                                    }
                                    else
                                    {
                                        status = "3";
                                        err = "有老師不存在於 Teacher 的DB";
                                    }
                                }
                            }
                        }

                        return Ok(new { status, record });
                    default:
                        return BadRequest(); // 不存在的功能BadRequest
                }
            }
            catch (Exception ex)
            {
                return BadRequest();
            }
        }
    }
}
