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 TEAMModelOS.SDK.Helper.Common.CollectionHelper;
using System.Text.Json;
using TEAMModelOS.SDK.Models;
using Microsoft.AspNetCore.Http;
using Azure.Cosmos;
using TEAMModelOS.SDK.Extension;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using Microsoft.Extensions.Options;
using System.Net.Http;
using TEAMModelOS.SDK.Context.Configuration;
using System.Net;

namespace TEAMModelOS.Controllers
{
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    //[Authorize(Roles = "teacher")]
    [Route("school/teacher")]
    [ApiController]
    public class SchoolTeacherController : Controller
    {

        private readonly AzureCosmosFactory _azureCosmos;
        private readonly AzureStorageFactory _azureStorage;
        private readonly Option _option;
        public SchoolTeacherController(AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, IOptionsSnapshot<Option> option)
        {
            _azureCosmos = azureCosmos;
            _azureStorage = azureStorage;
            _option = option?.Value;
        }
        /// <summary>
        /// 取得學校所有老師(不論加入狀態)
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("get-teacher-all")]
        public async Task<IActionResult> GetSchoolTeacherAll(JsonElement request)
        {
            var client = _azureCosmos.GetCosmosClient();
            //參數取得
            if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
            //string status_str = (request.TryGetProperty("join_status", out JsonElement status_json)) ? status_json.ToString() : "join";
            //資料取得
            List<object> teachers = new List<object>();
            await foreach (var item in client.GetContainer("TEAMModelOS", "School").GetItemQueryStreamIterator(queryText: $"SELECT c.id, c.name, c.classes, c.picture ,c.status, c.job, c.createTime, ARRAY_LENGTH(c.permissions) as permissionCount, c.size FROM c", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school_code}") }))
            {
                using var json = await JsonDocument.ParseAsync(item.ContentStream);
                if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                {
                    foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
                    {
                        teachers.Add(obj.ToObject<object>());
                    }
                }
            }

            return Ok(new { teachers });
        }

        /// <summary>
        /// 取得某位老師的權限
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("get-teacher-permission")]
        public async Task<IActionResult> GetPermissionById(JsonElement request)
        {
            var client = _azureCosmos.GetCosmosClient();
            //參數取得
            if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
            if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
            //老師權限資料取得
            object permissions = null;
            var response = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(id.ToString(), new PartitionKey($"Teacher-{school_code}"));
            if (response.Status == 200)
            {
                using var json = await JsonDocument.ParseAsync(response.ContentStream);
                if (json.RootElement.TryGetProperty("permissions", out JsonElement value))
                {
                    permissions = value.ToObject<object>();
                }
            }
            return Ok(new { permissions });
        }

        /// <summary>
        /// 取得權限總列表
        /// </summary>
        [ProducesDefaultResponseType]
        [HttpPost("get-teacher-authoritylist")]
        public async Task<IActionResult> GetSchoolAuthorityList()
        {
             
            Dictionary<string, object> dict = new Dictionary<string, object>
            {
                { "PartitionKey",  "authority"}
            };
            List<Authority> authoritylist = await _azureStorage.FindListByDict<Authority>(dict);
            return Ok(new { authoritylist });
        }

        /// <summary>
        /// 更新老師的權限(可複數)
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("upd-teacher-permission")]
        public async Task<IActionResult> UpdSchoolTeacherPermission(JsonElement request)
        {
            try
            {
                var client = _azureCosmos.GetCosmosClient();
                //參數取得
                if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
                request.TryGetProperty("ids", out JsonElement ids);
                request.TryGetProperty("mode", out JsonElement mode);
                request.TryGetProperty("pmAdd", out JsonElement pmAdd);
                request.TryGetProperty("pmRmv", out JsonElement pmRmv);
                List<string> pmAddList = new List<string>();
                List<string> pmRmvList = new List<string>();
                request.TryGetProperty("job", out JsonElement job);
                if (mode.GetString() == "multi")
                {
                    foreach (var pm in pmAdd.EnumerateArray())
                    {
                        pmAddList.Add(pm.GetString());
                    }
                    foreach (var pm in pmRmv.EnumerateArray())
                    {
                        pmRmvList.Add(pm.GetString());
                    }
                } else 
                {
                    foreach (var pm in pmAdd.EnumerateArray())
                    {
                        pmAddList.Add(pm.GetString());
                    }
                }

                //更新權限
                foreach (var id in ids.EnumerateArray())
                {
                    SchoolTeacher st = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<SchoolTeacher>(id.GetString(), new PartitionKey($"Teacher-{school_code}"));
                    if(mode.GetString() == "multi")
                    {
                        foreach (var pm in pmRmvList)
                        {
                            if(st.permissions.Contains(pm))
                            {
                                st.permissions.Remove(pm);
                            }
                        }
                        foreach (var pm in pmAddList)
                        {
                            if (!st.permissions.Contains(pm))
                            {
                                st.permissions.Add(pm);
                            }
                        }
                    } else
                    {
                        st.permissions = pmAddList;
                        st.job = (!string.IsNullOrEmpty(job.GetString())) ? job.GetString() : null;
                    }

                    await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<SchoolTeacher>(st, id.GetString(), new PartitionKey($"Teacher-{school_code}"));
                }
                return Ok(new {});
            }
            catch (Exception ex)
            {
                return BadRequest();
            }
        }

        /// <summary>
        /// 追加老師及學校加入狀態
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        [HttpPost("add-teacher-status")]
        public async Task<IActionResult> AddSchoolTeacher(JsonElement request)
        {
            var client = _azureCosmos.GetCosmosClient();
            //參數取得
            if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
            if (!request.TryGetProperty("user_list", out JsonElement user_list)) return BadRequest();
            if (!request.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
            //取得學校資訊
            var schresponse = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(school_code.ToString(), new PartitionKey("Base"));
            string schname = string.Empty;
            if (schresponse.Status == 200)
            {
                using var schjson = await JsonDocument.ParseAsync(schresponse.ContentStream);
                schjson.RootElement.TryGetProperty("name", out JsonElement jsonschname);
                schname = jsonschname.ToString();
            }
            else
            {
                return BadRequest();
            }
            try
            {
                foreach (var obj in user_list.EnumerateArray())
                {
                    obj.TryGetProperty("id", out JsonElement id);
                    obj.TryGetProperty("name", out JsonElement name);
                    obj.TryGetProperty("picture", out JsonElement picture);
                    //老師個人資料
                    var tresponse = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemStreamAsync(id.ToString(), new PartitionKey("Base"));
                    if(tresponse.Status == 200)
                    {
                        using var json = await JsonDocument.ParseAsync(tresponse.ContentStream);
                        Teacher teacher = json.ToObject<Teacher>();
                        var school = teacher.schools.FirstOrDefault(x => x.schoolId.Equals(school_code.GetString(), StringComparison.OrdinalIgnoreCase));
                        if (school != null)
                            school.status = grant_type.GetString();
                        else
                            teacher.schools.Add(new Teacher.School() { schoolId = school_code.GetString(), name = schname, status = grant_type.GetString() });
                        await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Teacher>(teacher, id.ToString(), new PartitionKey("Base"));
                    }
                    else
                    {
                        using var stream = new MemoryStream();
                        using var writer = new Utf8JsonWriter(stream);
                        writer.WriteStartObject();
                        writer.WriteString("pk", "Base");
                        writer.WriteString("code", "Base");
                        writer.WriteString("id", id.ToString());
                        writer.WriteString("name", name.ToString());
                        writer.WriteString("picture", picture.ToString());
                        writer.WriteNumber("size", 1);
                        writer.WriteNull("defaultSchool");
                        writer.WriteStartArray("schools");
                        writer.WriteStartObject();
                        writer.WriteString("schoolId", school_code.ToString());
                        writer.WriteString("name", schname);
                        writer.WriteString("status", grant_type.ToString());
                        writer.WriteEndObject();
                        writer.WriteEndArray();
                        writer.WriteEndObject();
                        writer.Flush();
                        await client.GetContainer("TEAMModelOS", "Teacher").CreateItemStreamAsync(stream, new PartitionKey("Base"));
                    }
                    //學校老師資料
                    var sresponse = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(id.ToString(), new PartitionKey($"Teacher-{school_code}"));
                    //SchoolTeacher schteacher = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<SchoolTeacher>(id.ToString(), new PartitionKey($"Teacher-{school_code}"));
                    if (sresponse.Status == 200)
                    {
                        using var json = await JsonDocument.ParseAsync(sresponse.ContentStream);
                        SchoolTeacher schteacher = json.ToObject<SchoolTeacher>();
                        schteacher.status = grant_type.ToString();
                        await client.GetContainer("TEAMModelOS", "School").ReplaceItemAsync<SchoolTeacher>(schteacher, id.ToString(), new PartitionKey($"Teacher-{school_code}"));
                    }
                    else
                    {
                        using var stream = new MemoryStream();
                        using var writer = new Utf8JsonWriter(stream);
                        writer.WriteStartObject();
                        writer.WriteString("pk", "Teacher");
                        writer.WriteString("code", $"Teacher-{school_code}");
                        writer.WriteString("id", id.ToString());
                        writer.WriteString("name", name.ToString());
                        writer.WriteString("picture", picture.ToString());
                        writer.WriteNull("job");
                        writer.WriteStartArray("roles");
                        writer.WriteStringValue("teacher");
                        writer.WriteEndArray();
                        writer.WriteStartArray("permissions");
                        writer.WriteEndArray();
                        writer.WriteString("status", grant_type.ToString());
                        writer.WriteNumber("createTime", DateTimeOffset.UtcNow.ToUnixTimeSeconds());
                        writer.WriteEndObject();
                        writer.Flush();
                        await client.GetContainer("TEAMModelOS", "School").CreateItemStreamAsync(stream, new PartitionKey($"Teacher-{school_code}"));
                    }
                }
                return Ok(new { });
            }
            catch(Exception ex)
            {
                return BadRequest();
            }
        }

        /// <summary>
        /// 學校變更老師加入狀態
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        //[AuthToken(Roles = "admin")]
        [HttpPost("upd-teacher-status")]
        public async Task<IActionResult> UpdSchoolTeacherStatus(JsonElement request)
        {
            try
            {
                if (!request.TryGetProperty("grant_type", out JsonElement grant_type)) return BadRequest();
                if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
                if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();

                var client = _azureCosmos.GetCosmosClient();
                //取得學校資訊
                var schresponse = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(school_code.ToString(), new PartitionKey("Base"));
                string schname = string.Empty;
                if (schresponse.Status == 200)
                {
                    using var schjson = await JsonDocument.ParseAsync(schresponse.ContentStream);
                    schjson.RootElement.TryGetProperty("name", out JsonElement jsonschname);
                    schname = jsonschname.ToString();
                }
                else
                {
                    return BadRequest();
                }

                //在老師表找出老師，處理該學校狀態 (老師基本資料應該要存在)
                Teacher teacher = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<Teacher>(id.ToString(), 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
                    teacher.schools.Add(new Teacher.School() { schoolId = school_code.GetString(), name = schname, status = grant_type.GetString() });
                await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Teacher>(teacher, id.ToString(), new PartitionKey("Base"));
                //在學校表處理該學校教師帳號的狀態
                var sresponse = await client.GetContainer("TEAMModelOS", "School").ReadItemStreamAsync(id.GetString(), 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.GetString(), new PartitionKey($"Teacher-{school_code}"));
                }
                else
                {
                    SchoolTeacher st = new SchoolTeacher()
                    {
                        pk = "Teacher",
                        code = $"Teacher-{school_code}",
                        createTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
                        id = teacher.id,
                        name = teacher.name,
                        picture = teacher.picture,
                        roles = new List<string>(new string[] { "teacher" }),
                        permissions = null,
                        status = grant_type.GetString()
                    };
                    var response = await client.GetContainer("TEAMModelOS", "School").CreateItemAsync(st, new PartitionKey($"Teacher-{school_code}"));
                }

                return Ok(new { });
            }
            catch (Exception ex)
            {
                return BadRequest();
            }
        }

        /// <summary>
        /// 學校移除老師跟學校關聯
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        //[AuthToken(Roles = "admin")]
        [HttpPost("rmv-teacher")]
        public async Task<IActionResult> RmvSchoolTeacher(JsonElement request)
        {
            try
            {
                if (!request.TryGetProperty("school_code", out JsonElement school_code)) return BadRequest();
                if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();

                var client = _azureCosmos.GetCosmosClient();
                //在老師表找出老師，刪除該學校 (老師基本資料應該要存在)
                Teacher teacher = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<Teacher>(id.ToString(), new PartitionKey("Base"));
                var school = teacher.schools.RemoveAll(x => x.schoolId.Equals(school_code.GetString(), StringComparison.OrdinalIgnoreCase));
                await client.GetContainer("TEAMModelOS", "Teacher").ReplaceItemAsync<Teacher>(teacher, id.ToString(), new PartitionKey("Base"));
                //移除學校表中的老師document
                var sresponse = await client.GetContainer("TEAMModelOS", "School").DeleteItemStreamAsync(id.GetString(), new PartitionKey($"Teacher-{school_code}"));

                return Ok(new { });
            }
            catch (Exception ex)
            {
                return BadRequest();
            }
        }

        /// <summary>
        /// 取得CoreID資訊
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [ProducesDefaultResponseType]
        //[AuthToken(Roles = "admin")]
        [HttpPost("get-coreuser")]
        public async Task<IActionResult> GetUserFromCoreID(JsonElement request)
        {
            try
            {
                string url = BaseConfigModel.Configuration["HaBookAuth:CoreId:userinfo"];
                HttpClient client = new HttpClient();
                var content = new StringContent(request.ToString(), Encoding.UTF8, "application/json");
                HttpResponseMessage responseMessage = await client.PostAsync(url, content);
                if(responseMessage.StatusCode == HttpStatusCode.OK)
                {
                    string responseBody = responseMessage.Content.ReadAsStringAsync().Result;
                    return Ok(responseBody);
                }
                else
                {
                    return BadRequest();
                }
            }
            catch (Exception ex)
            {
                return BadRequest();
            }
        }
    }
}
