using Azure.Cosmos;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Sas;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using TEAMModelOS.Models;
using TEAMModelOS.SDK.Models;
using TEAMModelOS.SDK.DI;
using TEAMModelOS.SDK.Extension;
using TEAMModelOS.Filter;
using TEAMModelOS.SDK.Models.Cosmos;
using HTEXLib.COMM.Helpers;

namespace TEAMModelOS.Controllers
{
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    //[Authorize(Roles = "IES5")]
    [Route("teacher/init")]
    [ApiController]
    public class InitController : ControllerBase
    {
        private readonly AzureCosmosFactory _azureCosmos;
        private readonly AzureStorageFactory _azureStorage;
        private readonly DingDing _dingDing;
        private readonly Option _option;

        public InitController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, DingDing dingDing, IOptionsSnapshot<Option> option)
        {
            _azureCosmos = azureCosmos;
            _azureStorage = azureStorage;
            _dingDing = dingDing;
            _option = option?.Value;
        }

        //TODO 此API需處理對應前端返回的相關數據
        [ProducesDefaultResponseType]
        [HttpPost("get-teacher-info")]

        public async Task<IActionResult> GetTeacherInfo(JsonElement request)
        {
            //Debug
            //string json = System.Text.Json.JsonSerializer.Serialize(id_token);
            try
            {
                if (!request.TryGetProperty("id_token", out JsonElement id_token)) return BadRequest();
                var jwt = new JwtSecurityToken(id_token.GetString());
                //TODO 此驗證IdToken先簡單檢查，後面需向Core ID新API，驗證Token
                if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.OrdinalIgnoreCase)) return BadRequest();
                var id = jwt.Payload.Sub;
                jwt.Payload.TryGetValue("name", out object name);
                jwt.Payload.TryGetValue("picture", out object picture);
               List<object> schools = new List<object>();
               // object schools = null;
                string defaultschool = null;
                //TODO 取得Teacher 個人相關數據(課程清單、虛擬教室清單、歷史紀錄清單等)，學校數據另外API處理，多校切換時不同
                var client = _azureCosmos.GetCosmosClient();
                var response = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemStreamAsync(id, new PartitionKey("Base"));

                //老師個人資料(含初始化)
                if (response.Status == 200)
                {
                    var json = await JsonDocument.ParseAsync(response.ContentStream);
                    if (json.RootElement.TryGetProperty("schools", out JsonElement value))
                    {

                        foreach (var obj in value.EnumerateArray())
                        {
                            string statusNow = obj.GetProperty("status").ToString();
                            if (statusNow == "join" || statusNow == "invite" || statusNow == "request")
                            {
                                dynamic schoolExtobj = new ExpandoObject();
                                var schoolJson = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync($"{obj.GetProperty("schoolId")}", new PartitionKey("Base"));
                                var school = await JsonDocument.ParseAsync(schoolJson.ContentStream);
                                schoolExtobj.schoolId = obj.GetProperty("schoolId");
                                schoolExtobj.name = obj.GetProperty("name");
                                schoolExtobj.status = obj.GetProperty("status");
                                if (obj.TryGetProperty("time", out JsonElement time)) {
                                    schoolExtobj.time = obj.GetProperty("time");
                                }
                                schoolExtobj.picture = school.RootElement.GetProperty("picture");
                                schools.Add(schoolExtobj);
                            }
                        }
                        //schools = value.ToObject<object>();
                    }
                    //預設學校ID
                    if (json.RootElement.TryGetProperty("defaultSchool", out JsonElement valueD) && !string.IsNullOrEmpty(valueD.ToString()))
                    {
                        defaultschool = valueD.ToString();
                    }
                }
                else
                {
                    //如果沒有，則初始化Teacher基本資料到Cosmos

                    using var stream = new MemoryStream();
                    using var writer = new Utf8JsonWriter(stream); //new JsonWriterOptions() { Indented = true }
                    writer.WriteStartObject();
                    writer.WriteString("pk", "Base");
                    writer.WriteString("code", "Base");
                    writer.WriteString("id", id);
                    writer.WriteString("name", name?.ToString());
                    writer.WriteString("picture", picture?.ToString());
                    writer.WriteNumber("size", 1);
                    writer.WriteNull("defaultSchool");
                    writer.WriteStartArray("schools");
                    writer.WriteEndArray();
                    writer.WriteEndObject();
                    writer.Flush();
                    //Debug
                    //string teacher = Encoding.UTF8.GetString(stream.ToArray());
                    response = await _azureCosmos.GetCosmosClient().GetContainer("TEAMModelOS", "Teacher").CreateItemStreamAsync(stream, new PartitionKey("Base"));
                }

                //私人課程
                List<object> courses = new List<object>();
                await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryStreamIterator(queryText: $"select c.id, c.name, c.classes, c.notice ,c.scope from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Course-{id}") }))
                {
                    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())
                        {
                            courses.Add(obj.ToObject<object>());
                        }
                    }
                }

                //老師個人課綱  TODO 暂时不取
                List<SyllabusRole> syllabus = new List<SyllabusRole>();
                //await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher").GetItemQueryStreamIterator(queryText: $"SELECT c.id, c.name, c.scope, c.resourceCount, c.itemCount, c.children from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Syllabus-{id}") }))
                //{
                //    var jsons = await JsonDocument.ParseAsync(item.ContentStream);
                //    if (jsons.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                //    {
                //        foreach (var obj in jsons.RootElement.GetProperty("Documents").EnumerateArray())
                //        {
                //            SyllabusRole syllabusRole = new SyllabusRole();
                //            syllabusRole.id = obj.GetProperty("id").ToString();
                //            syllabusRole.name = obj.GetProperty("name").ToString();
                //            syllabusRole.resourceCount = obj.GetProperty("resourceCount").GetUInt16();
                //            syllabusRole.itemCount = obj.GetProperty("itemCount").GetUInt16();
                //            List<Syllabus> syllabusList = obj.GetProperty("children").ToObject<List<Syllabus>>();
                //            syllabusList.Insert(0, new Syllabus { id = syllabusRole.id, name = syllabusRole.name, pid = "", order = 0 });
                //            syllabusList = syllabusList.OrderBy(x => x.order).ToList();
                //            syllabusRole.structure = CreateSyllabusTree(syllabusList);
                //            syllabus.Add(syllabusRole);
                //        }
                //        //[DEBUG] string jsonString = System.Text.Json.JsonSerializer.Serialize(syllabusRoles);
                //    }
                //}

                //換取AuthToken，提供給前端
                var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id, name?.ToString(), picture?.ToString(), _option.JwtSecretKey, roles: new[] { "teacher"});

                //取得Teacher Blob 容器位置及SAS 
                var container = _azureStorage.GetBlobContainerClient(id);
                await container.CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建Teacher私有容器，如存在則不做任何事，保障容器一定存在
                var (blob_uri, blob_sas) = _azureStorage.GetBlobContainerSAS(id, BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete);

                return Ok(new { auth_token, blob_uri, blob_sas, schools, defaultschool, courses });

            }
            catch (Exception ex)
            {
                await _dingDing.SendBotMsg($"IES5，{_option.Location}，Teacher/GetTeacherInfo()\n{ex.Message}{ex.StackTrace}", GroupNames.醍摩豆服務運維群組);
                return BadRequest();
            }
        }

        //TODO 此API需處理對應前端返回的相關數據
        [ProducesDefaultResponseType]
        [HttpPost("get-school-info")]        
        public async Task<IActionResult> GetSchoolInfo(JsonElement requert)
        {

            if (!requert.TryGetProperty("id_token", out JsonElement id_token)) return BadRequest();
            if (!requert.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
            var jwt = new JwtSecurityToken(id_token.GetString());
            if (!jwt.Payload.Iss.Equals("account.teammodel", StringComparison.Ordinal)) return BadRequest();
            var id = jwt.Payload.Sub;

            var client = _azureCosmos.GetCosmosClient();

            //權限token
            jwt.Payload.TryGetValue("name", out object name);
            jwt.Payload.TryGetValue("picture", out object picture);
            List<string> roles = new List<string>();
            List<string> permissions = new List<string>();
            
            var response = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(id, new PartitionKey($"Teacher-{school_code}"));
            if (response.Status == 200)
            {
                using var json = await JsonDocument.ParseAsync(response.ContentStream);

                if (json.RootElement.TryGetProperty("roles", out JsonElement _roles) && _roles.ValueKind != JsonValueKind.Null)
                {
                    foreach (var obj in _roles.EnumerateArray())
                    {
                        roles.Add(obj.GetString());
                    }
                }
                if (json.RootElement.TryGetProperty("permissions", out JsonElement _permissions) && _permissions.ValueKind != JsonValueKind.Null)
                {
                    foreach (var obj in _permissions.EnumerateArray())
                    {
                        permissions.Add(obj.GetString());
                    }
                }
            }
            else //無此學校資料
            {
                return BadRequest();
            }
            if (roles.Count == 0)
            {
                roles.Add("teacher");
                roles.Add("student");
            }
            //TODO JJ，更新Token时，在取得学校资讯时，没有传入schoolId
            var auth_token = JwtAuthExtension.CreateAuthToken(_option.HostName, id, name?.ToString(), picture?.ToString(), _option.JwtSecretKey, schoolID: school_code.ToString(), roles: roles.ToArray(), permissions: permissions.ToArray());

            //TODO JJ，调整为取得学校基础设置数据，取代下方學校學制、年級
            object school_base = null;
            response = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(school_code.ToString(), new PartitionKey("Base"));
            if (response.Status == 200)
            {
                using var json = await JsonDocument.ParseAsync(response.ContentStream);
                school_base = json.RootElement.ToObject<object>();                
            }

            //取得班级
            List<object> school_classes = new List<object>();
            await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: $"SELECT c.id,c.x,c.y,c.name,c.year,c.teacher,c.periodId,c.gradeId,c.room,c.sn,c.no,c.style,c.status,c.openType,c.scope, ARRAY_LENGTH(c.students) AS studCount 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())
                {                   
                    school_classes.Add(classeinfo.ToObject<object>());
                }
            }
            //取得教室
            List<Room> school_rooms = new List<Room>();
            await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryIterator<Room>(queryText: $"select value(c) from c ",
            requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Room-{school_code}") }))
            {
                school_rooms.Add(item);
            }
            //List<object> periods = new List<object>();
            //List<object> grades = new List<object>();
            //var responsesch = await client.GetContainer("TEAMModelOS", "School").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);
            //                }
            //            }
            //        }
            //    }
            //}

            //該老師排定的學校課程
            List<object> school_courses = new List<object>();
            var query = $"SELECT c.id, c.name, c.teacher, cc.course, c.scope FROM c JOIN cc IN c.courses JOIN cct IN cc.teachers WHERE cct.id = '{id}'";
            await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"CourseManagement-{school_code}") }))
            {
                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())
                    {
                        //班級
                        string classIdNow = obj.GetProperty("id").ToString();
                        dynamic classExtobj = new ExpandoObject();
                        classExtobj.code = $"Class-{school_code}";
                        classExtobj.id = classIdNow;
                        classExtobj.name = obj.GetProperty("name").ToString();
                        classExtobj.teacher = obj.GetProperty("teacher").ToObject<object>();
                        classExtobj.scope = obj.GetProperty("scope").ToString();
                        //課程
                        obj.TryGetProperty("course", out JsonElement courseNow);
                        string courseIdNow = courseNow.GetProperty("id").ToString();
                        var courseExist = school_courses.Where((dynamic x) => x.id == courseIdNow).FirstOrDefault();
                        if (courseExist == null)
                        {
                            dynamic courseExtobj = new ExpandoObject();
                            courseExtobj.id = courseIdNow;
                            courseExtobj.name = courseNow.GetProperty("name").ToString();
                            courseExtobj.scope = courseNow.GetProperty("scope").ToString();
                            courseExtobj.classes = new List<object>();
                            courseExtobj.classes.Add(classExtobj);
                            school_courses.Add(courseExtobj);
                        }
                        else
                        {
                            courseExist.classes.Add(classExtobj);
                        }
                    }
                }
            }

            //校本課綱 [式樣未定 先不取]
            List<SyllabusRole> school_syllabus = new List<SyllabusRole>();
            //await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: $"SELECT c.id, c.name, c.period, c.grade, c.semester, c.subject, c.scope, c.resourceCount, c.itemCount, c.children from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Syllabus-{school_code}") }))
            //{
            //    var jsons = await JsonDocument.ParseAsync(item.ContentStream);
            //    if (jsons.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
            //    {
            //        foreach (var obj in jsons.RootElement.GetProperty("Documents").EnumerateArray())
            //        {
            //            SyllabusRole syllabusRole = new SyllabusRole();
            //            syllabusRole.id = obj.GetProperty("id").ToString();
            //            syllabusRole.name = obj.GetProperty("name").ToString();
            //            syllabusRole.period = obj.GetProperty("period");
            //            syllabusRole.grade = obj.GetProperty("grade");
            //            syllabusRole.semester = obj.GetProperty("semester");
            //            syllabusRole.subject = obj.GetProperty("subject");
            //            syllabusRole.resourceCount = obj.GetProperty("resourceCount").GetUInt16();
            //            syllabusRole.itemCount = obj.GetProperty("itemCount").GetUInt16();
            //            List<Syllabus> syllabusList = obj.GetProperty("children").ToObject<List<Syllabus>>();
            //            syllabusList.Insert(0, new Syllabus { id = syllabusRole.id, name = syllabusRole.name, pid = "", order = 0 });
            //            syllabusList = syllabusList.OrderBy(x => x.order).ToList();
            //            syllabusRole.structure = CreateSyllabusTree(syllabusList);
            //            syllabus.Add(syllabusRole);
            //        }
            //        //[DEBUG] string jsonString = System.Text.Json.JsonSerializer.Serialize(syllabusRoles);
            //    }
            //}

            //取得School Blob 容器位置及SAS
            string school_code_blob = school_code.GetString().ToLower();
            var container = _azureStorage.GetBlobContainerClient(school_code_blob);
            await container.CreateIfNotExistsAsync(PublicAccessType.None); //嘗試創建School容器，如存在則不做任何事，保障容器一定存在
            var (blob_uri, blob_sas) = (roles.Contains("admin") || permissions.Contains("schoolAc-upd")) ? _azureStorage.GetBlobContainerSAS(school_code_blob, BlobContainerSasPermissions.Write | BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List | BlobContainerSasPermissions.Delete) : _azureStorage.GetBlobContainerSAS(school_code_blob, BlobContainerSasPermissions.Read | BlobContainerSasPermissions.List| BlobContainerSasPermissions.Write);

            return Ok(new { auth_token, blob_uri, blob_sas, school_base, school_courses, school_syllabus, school_classes , school_rooms });
        }

        [ProducesDefaultResponseType]
        //[AuthToken(Roles = "teacher")]
        [HttpPost("get-school-list")]
        public async Task<IActionResult> GetSchoolList()
        {
            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.name,c.region,c.province,c.city,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="requert"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [AuthToken(Roles = "teacher")]
        [HttpPost("join-school")]
        public async Task<IActionResult> JoinSchool(JsonElement requert)
        {
            try
            {
                if (!requert.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();  //"invite":學校邀請 "request":老師申請 "join":"成為學校老師"，leave 离开，cancel 取消。
                if (!requert.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
                if (!requert.TryGetProperty("school_name", out JsonElement school_name)) return BadRequest();
                string authtoken = HttpContext.GetXAuth("AuthToken");
                if (string.IsNullOrEmpty(authtoken)) return BadRequest();
                var jwt = new JwtSecurityToken(authtoken);
                var id = jwt.Payload.Sub;
                var schoolcode = jwt.Payload.Azp;
                var Claims = jwt.Payload.Claims;
                jwt.Payload.TryGetValue("name", out object name);
                jwt.Payload.TryGetValue("picture", out object picture);

                var client = _azureCosmos.GetCosmosClient();
                //在老師表找出老師，處理該學校狀態 (老師基本資料應該要存在)
                Teacher teacher = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<Teacher>(id, new PartitionKey("Base"));
                if (teacher.schools == null)
                    teacher.schools = new List<Teacher.School>();
                var school = teacher.schools?.FirstOrDefault(x => x.schoolId.Equals(school_code.GetString(), StringComparison.OrdinalIgnoreCase));
                if (school != null)
                    school.status = grant_type.GetString();
                else
                {
                    long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                    teacher.schools.Add(new Teacher.School() { schoolId = school_code.GetString(), name = school_name.GetString(), status = grant_type.GetString() ,time= now });
                }
                if (grant_type.GetString() == "leave" || grant_type.GetString() == "cancel")
                {
                    if (teacher.schools.IsNotEmpty())
                    {
                        //获取之前已经加入的学校或者申请的学校
                        var inSchools = teacher.schools.Where(x => x.schoolId == school_code.GetString()).ToList();
                        if (inSchools.IsNotEmpty())
                        {
                            inSchools.ForEach(x => teacher.schools.Remove(x));
                        }
                    }
                    await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Teacher>(teacher, id, new PartitionKey("Base"));
                    var sresponse = await client.GetContainer("TEAMModelOS", "School").DeleteItemStreamAsync(id, new PartitionKey($"Teacher-{school_code}"));
                    return Ok(new { stauts = 1 });
                }
                else {
                    await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Teacher>(teacher, id, new PartitionKey("Base"));
                    //在學校表處理該學校教師帳號的狀態
                    var sresponse = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(id, new PartitionKey($"Teacher-{school_code}"));
                    if (sresponse.Status == 200)
                    {
                        using var json = await JsonDocument.ParseAsync(sresponse.ContentStream);
                        SchoolTeacher steacher = json.ToObject<SchoolTeacher>();
                        steacher.status = grant_type.GetString();
                        var response = await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync(steacher, id, new PartitionKey($"Teacher-{school_code}"));
                    }
                    else
                    {
                        SchoolTeacher st = new SchoolTeacher()
                        {
                            pk = "Teacher",
                            code = $"Teacher-{school_code}",
                            createTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
                            id = id,
                            name = name.ToString(),
                            picture = picture?.ToString(), //TODO JJ，原本的判断会出现报错，没检查null却又去ToString
                            permissions = new List<string>(),
                            roles = new List<string>() { "teacher" },
                            status = grant_type.GetString()
                        };
                        var response = await client.GetContainer("TEAMModelOS", "School").CreateItemAsync(st, new PartitionKey($"Teacher-{school_code}"));
                    }
                    return Ok(new { stauts = 1 });
                }
            }
            catch (Exception ex)
            {
                await _dingDing.SendBotMsg($"TEAMModel，{_option.Location}，Init/JoinSchool()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
                return BadRequest();
            }
        }


        //課綱的model先記在下面，待式樣確定後再轉換
        private List<SyllabusNode> CreateSyllabusTree(List<Syllabus> syllabuses)
        {
            List<SyllabusNode> nodes = new List<SyllabusNode>();

            foreach (var syllabus in syllabuses)
            {
                if (syllabus.pid == "")
                    nodes.Add(new SyllabusNode { id = syllabus.id, name = syllabus.name });
                else
                {
                    CreateNode(nodes, syllabus);
                }
            }
            return nodes;
        }

        private void CreateNode(List<SyllabusNode> nodes, Syllabus parent)
        {
            foreach (var node in nodes)
            {
                if (node.id == parent.pid)
                {
                    node.children.Add(new SyllabusNode { id = parent.id, name = parent.name });
                }
                else
                {
                    CreateNode(node.children, parent);
                }
            }
        }

        public class SyllabusRole
        {
            public string id { get; set; }
            public string name { get; set; }
            public object period { get; set; }
            public object semester { get; set; }
            public object grade { get; set; }
            public object subject { get; set; }
            public int resourceCount { get; set; }
            public int itemCount { get; set; }
            public object structure { get; set; }
        }

        public class Syllabus
        {
            public string id { get; set; }
            public string name { get; set; }
            public string pid { get; set; }
            public int order { get; set; }
        }

        public class SyllabusNode
        {
            public string id { get; set; }
            public string name { get; set; }
            public List<SyllabusNode> children { get; set; }

            public SyllabusNode()
            {
                children = new List<SyllabusNode>();
            }
        }
    }
}
