using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using TEAMModelOS.SDK.Context.Configuration;
using TEAMModelOS.SDK;
using TEAMModelOS.SDK.Helper.Common.JsonHelper;
using TEAMModelOS.SDK.Module.AzureBlob.Configuration;
using TEAMModelOS.SDK.DI;
using System.Net.Http;
using TEAMModelOS.SDK.Helper.Security.ShaHash;
using TEAMModelOS.SDK.Extension;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.AspNetCore.Authorization;
using TEAMModelOS.Filter;
using StackExchange.Redis;
using Azure.Messaging.ServiceBus;
using static TEAMModelOS.SDK.DI.AzureStorageBlobExtensions;
using System.Linq;

namespace TEAMModelOS.Controllers.Core
{
    [Route("blob")]
    [ApiController]
    public class BlobController : ControllerBase
    {

        private readonly AzureStorageFactory _azureStorage;
        private readonly IHttpClientFactory _clientFactory;
        private readonly AzureRedisFactory _azureRedis;
        private readonly AzureServiceBusFactory _serviceBus;
        public BlobController(AzureStorageFactory azureStorage, AzureServiceBusFactory serviceBus, IHttpClientFactory clientFactory, AzureRedisFactory azureRedis)
        {
            _azureStorage = azureStorage;
            _clientFactory = clientFactory;
            _serviceBus = serviceBus;
            _azureRedis = azureRedis;
        }

        /// <summary>
        /// 获取某个容器的只读权限
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost("sas-r")]
        public IActionResult BlobSasR(BlobSas request)
        {
            ///返回金钥过期时间 
            // Dictionary<string, object> dict = await azureBlobDBRepository.GetBlobSasUri(request.@params,true);
            // dict.Add(d.Key, d.Value);
            return Ok(_azureStorage.GetContainerSasUri(request, true));
        }
        /// <summary>
        /// 某个文件的上传SAS rcw权限
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost("sas-rcwld")]
        public IActionResult BlobSasRCW(BlobSas request)
        {
            ///返回金钥过期时间
            // Dictionary<string,object> dict=  await azureBlobDBRepository.GetBlobSasUri(request.@params,false);
            //   Dictionary<string, object> dict = ;
            //dict.Add(d.Key, d.Value);
            return Ok(_azureStorage.GetContainerSasUri(request, false));
        }

        /// <summary>
        /// 删除prefix
        /// 
        /// {"cntr":"","prefix":"res/test"}
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost("delete-prefix")]
        [AuthToken(Roles = "teacher,admin")]
        public async Task<IActionResult> DeletePrefix(JsonElement json)
        {
            var (id,_,_,school) = HttpContext.GetAuthTokenInfo();
            string blobContainerName = null;
            string prefix = null;
            if (json.TryGetProperty("cntr", out JsonElement cntr)) {
                var cntrs= cntr.ToString();
              
                if (cntrs.Equals(id))
                {
                    blobContainerName = id;
                }
                else if(cntrs.Equals(school))
                {
                    blobContainerName = school;
                }
                else
                {
                    return BadRequest("只能删除本人管理的文件夹");
                }
            }
            if (json.TryGetProperty("prefix", out JsonElement prefixjson))
            {
                prefix = prefixjson.ToString();
            }
            if (prefix != null && blobContainerName != null)
            {
                var status = await _azureStorage.GetBlobServiceClient().DelectBlobs(blobContainerName, prefix);
                return Ok(new { status });
            }
            else {
                return BadRequest();
            }
            
        }

        /// <summary>
        /// 删除多个Url
        /// 
        /// {"cntr":"","urls":["res/test/1.json","res/test/2.json"]}
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost("delete-blobs")]
        [AuthToken(Roles = "teacher,admin")]
        public async Task<IActionResult> DeleteBlobs(JsonElement json)
        {
           var (id, _, _, school) = HttpContext.GetAuthTokenInfo();
            string blobContainerName = null;
            List<Uri> uris = null;
            if (json.TryGetProperty("cntr", out JsonElement cntr))
            {
                var  cntrs = cntr.ToString();
                if (cntrs.Equals(id))
                {
                    blobContainerName = id;
                }
                else if (cntrs.Equals(school))
                {
                    blobContainerName = school;
                }
                else {
                    return BadRequest("只能删除本人管理的文件");
                }
            }
            bool flag = true;
            if (json.TryGetProperty("urls", out JsonElement urlsjson)) {
                uris= urlsjson.ToObject<List<Uri>>();
                uris.ForEach(x => {
                    (string, string) a = BlobUrlString(x.ToString());
                    string ContainerName = a.Item1;
                    string BlobName = a.Item2;
                    if (ContainerName!=blobContainerName) {
                        flag = false;
                    }
                });
            }
            if (flag)
            {
                if (blobContainerName != null && uris != null && uris.Count > 0)
                {
                    var status = await _azureStorage.GetBlobServiceClient().DelectBlobs(blobContainerName, uris);
                    return Ok(new { status });
                }
                else
                {
                    return BadRequest();
                }
            }
            else {
                return BadRequest("只能删除本人管理的文件");
            }
            
        }


        /// <summary>
        /// 链接只读（读）
        /// </summary>
        /// <param name="azureBlobSASDto"></param>
        /// <returns></returns>
        [HttpPost("sas-url-r")]
        public IActionResult GetContainerSASRead(JsonElement azureBlobSASDto)
        {
            azureBlobSASDto.TryGetProperty("url", out JsonElement azureBlobSAS);
            //string azureBlobSAS = azureBlobSASDto;
            (string, string) a = BlobUrlString(azureBlobSAS.ToString());
            string ContainerName = a.Item1;
            string BlobName = a.Item2;
            bool flg = IsBlobName(BlobName);
            if (flg)
            {
                return Ok(_azureStorage.GetBlobSasUriRead(ContainerName, BlobName));
            }
            else
            {
                return BadRequest("文件名错误");
            };
        }     
      

        
        /// <summary>
        /// 获取文件内容
        /// </summary>
        /// <param name="azureBlobSASDto"></param>
        /// <returns></returns>
        [HttpPost("get-text")]
        public async Task<IActionResult> GetText(JsonElement request)
        {
            request.TryGetProperty("code", out JsonElement code); 
            string azureBlobSAS = System.Web.HttpUtility.UrlDecode(code.ToString(), Encoding.UTF8);
            (string, string) a = BlobUrlString(azureBlobSAS);
            string ContainerName = a.Item1;
            string BlobName = a.Item2;
            bool flg = IsBlobName(BlobName);
            if (flg)
            {
                //TODO 需驗證
                BlobAuth blobAuth= _azureStorage.GetBlobSasUriRead(ContainerName, BlobName);
                var  response= await _clientFactory.CreateClient().GetAsync(new Uri(blobAuth.url + blobAuth.sas));
                response.EnsureSuccessStatusCode();
                using var json = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());                
                return  Ok(json.RootElement);
            }
            else
            {
                return BadRequest("文件名错误");
            };

        }
        
        /// <summary>
        /// 测试单个文本内容的上传
        /// </summary>
        /// <param name="azureBlobSASDto"></param>
        /// <returns></returns>
        [HttpPost("get-blobsize")]
        public async Task<ActionResult> GetBlobsSize(JsonElement request)
        {
            request.TryGetProperty("containerName", out JsonElement containerName);
            request.TryGetProperty("cache", out JsonElement cache);
            var name =containerName.GetString();
            try {
                if (cache.GetBoolean())
                {
                    long blobsize = 0;
                    RedisValue value = default;
                    value = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", name);
                    if (value != default && !value.IsNullOrEmpty)
                    {
                        JsonElement record = value.ToString().ToObject<JsonElement>();
                        if (record.TryGetInt64(out  blobsize))
                        {
                           
                        }
                    }
                    Dictionary<string, double> catalog = new Dictionary<string, double>();
                    SortedSetEntry[] Scores = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Blob:Catalog:{name}");
                    if (Scores != null )
                    {
                        foreach (var score in Scores) {
                            double val = score.Score;
                            string key = score.Element.ToString();
                            catalog.Add(key, val);
                        }   
                    }
                    return Ok(new { size = blobsize, catalog= catalog });
                }
            } catch { }
            var client = _azureStorage.GetBlobContainerClient(name);
            var size = await client.GetBlobsCatalogSize();
            await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", name, size.Item1);
            foreach (var key in size.Item2.Keys) {
                await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Blob:Catalog:{name}", key);
                await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{name}", key, size.Item2[key].HasValue?size.Item2[key].Value:0);
            }
            return Ok(new { size = size.Item1, catalog = size.Item2 });
        }

        /// <summary>
        /// 测试单个文本内容的上传
        /// {"containerName":"hbcn","urls":["video/xxx.mp4","res/xxx.png"]}
        /// </summary>
        /// <param name="azureBlobSASDto"></param>
        /// <returns></returns>
        [HttpPost("check-blobsize")]
        public async Task<ActionResult> checkBlobsSize(JsonElement request)
        {
            request.TryGetProperty("containerName", out JsonElement containerName);
            request.TryGetProperty("urls", out JsonElement optUrls);
            var name = containerName.GetString();
            var urls = optUrls.ToObject<List<string>>();
            var client = _azureStorage.GetBlobContainerClient(name);
            var urlsSize = await client.GetBlobsSize(urls);
            return Ok(new {  urlsSize });
        }

        /*
         * 
         {
            "containerName": "hbcn",
            "cache": true,
            "optUrls": [
                {
                    "url": "video%2F37Z888piCvm9.mp4",
                    "size": 1000
                }
            ]
         }
        */
        /// <summary>
        /// 测试单个文本内容的上传
        /// {"containerName":"hbcn","uploadSize":5000,"optUrls":[{"url":"video/37Z888piCvm9.mp4","size":0},{}]}
        /// </summary>
        /// <param name="azureBlobSASDto"></param>
        /// <returns></returns>
        [HttpPost("update-blobsize")]
        public async Task<ActionResult> updateBlobsSize(JsonElement request)
        {
            request.TryGetProperty("containerName", out JsonElement containerName);
            request.TryGetProperty("optUrls", out JsonElement optUrls);
            var name = containerName.GetString();
            var urls = optUrls.ToObject<List<OptUrl>>();
            var client = _azureStorage.GetBlobContainerClient(name);
            var disSize = urls.Select(x => x.size).Sum();
            RedisValue value = default;
            long blobSize = 0;
            value = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", name);
            if (value != default && !value.IsNullOrEmpty)
            {
                JsonElement record = value.ToString().ToObject<JsonElement>();
                if (record.TryGetInt64(out blobSize))
                {
                }
            }
            long? useSize = blobSize + disSize;
            await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", name, useSize);
             
            foreach (var x in urls) {
                await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{name}", System.Web.HttpUtility.UrlDecode(x.url, Encoding.UTF8).Split("/")[0], x.size);
            }
            var messageBlob = new ServiceBusMessage(new {id=Guid.NewGuid().ToString(), progress = "update",name=name}.ToJsonString());
            messageBlob.ApplicationProperties.Add("name", "Blob");
            await _serviceBus.GetServiceBusClient().SendMessageAsync("active-task", messageBlob);
            return Ok(new { size=useSize });
        }

        private static (string, string) BlobUrlString(string sasUrl)
        {
            sasUrl = sasUrl.Substring(8);
            string[] sasUrls = sasUrl.Split("/");
            string ContainerName;
            ContainerName = sasUrls[1].Clone().ToString();
            string item = sasUrls[0] + "/" + sasUrls[1] + "/";
            string blob = sasUrl.Replace(item, "");
            return (ContainerName, blob);
        }
        public static bool IsBlobName(string BlobName)
        {
            return System.Text.RegularExpressions.Regex.IsMatch(BlobName,
             @"(?!((^(con)$)|^(con)\\..*|(^(prn)$)|^(prn)\\..*|(^(aux)$)|^(aux)\\..*|(^(nul)$)|^(nul)\\..*|(^(com)[1-9]$)|^(com)[1-9]\\..*|(^(lpt)[1-9]$)|^(lpt)[1-9]\\..*)|^\\s+|.*\\s$)(^[^\\\\\\:\\<\\>\\*\\?\\\\\\""\\\\|]{1,255}$)");
        }
    }
}
