using Aliyun.OSS;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Wicture.DbRESTFul;

namespace JiaZhiQuan.Common.AliOSS
{
    public class FileUpload
    {
        private static readonly string[] ImageFileExtensions = new[] { "png", "jpg", "jpeg", "gif", "bmp" };

        public async static Task<UploadResult> UploadFromRequest(IHttpClientFactory httpClientFactory, IFormFile file, string destFileName, string destDir, OSSConfig config, int maxSize = 2, bool isImage = true)
        {
            OssClient ossClient = new OssClient(config.EndPoint, config.AccessKeyId, config.AccessKeySecret);
            return await UploadFromRequest(httpClientFactory, file, destFileName, destDir, config, ossClient, maxSize, isImage);
        }

        public class UploadResult
        {
            public int width { get; set; }
            public int height { get; set; }
            public string url { get; set; }
        }

        public async static Task<UploadResult> UploadFromRequest(IHttpClientFactory httpClientFactory, IFormFile file, string destFileName, string destDir, OSSConfig config, OssClient ossClient, int maxSize = 2, bool isImage = true)
        {
            var extension = Path.GetExtension(file.FileName);
            if (isImage && ImageFileExtensions.All(e => !extension.ToLower().Equals("." + e)))
            {
                throw new LogicalException("仅支持上传图片格式", ErrorCodes.UploadFileFormatError);
            }

            if (file.Length > maxSize * 1024 * 1024)
            {
                throw new LogicalException("上传的" + (isImage ? "图片" : "文件") + "不能大于" + maxSize + "M", ErrorCodes.UploadFileSizeLimitError);
            }

            var dir = destDir.Trim(new char[] { '\\', '/' });
            if (string.IsNullOrEmpty(dir))
            {
                destFileName = destFileName.Trim(new char[] { '\\', '/' }) + extension;
            }
            else
            {
                destFileName = dir + "/" + destFileName.Trim(new char[] { '\\', '/' }) + extension;
            }

            using Stream fileStream = file.OpenReadStream();

            if (isImage)
            {
                int width = 0;
                int height = 0;

                string url = await UploadToAliyun(destFileName, fileStream, config, ossClient);

                var reqUrl = string.IsNullOrEmpty(config.InternalDomainUrl) ? url : config.InternalDomainUrl + destFileName;

                var client = httpClientFactory.CreateClient();
                client.Timeout = new TimeSpan(0, 0, 2);
                try
                {
                    var content = JToken.Parse(await client.GetStringAsync(reqUrl + "?x-oss-process=image/info"));
                    width = content.Value<JToken>("ImageWidth").Value<int>("value");
                    height = content.Value<JToken>("ImageHeight").Value<int>("value");
                }
                catch (Exception ex)
                {
                    LoggerManager.Logger.Error(ex, "获取图片属性出错 >>> " + reqUrl + "\r\n" + ex.Message);
                }
                return new UploadResult()
                {
                    url = url,
                    width = width,
                    height = height
                };
            }
            else
            {
                var url = await UploadToAliyun(destFileName, fileStream, config, ossClient);
                return new UploadResult()
                {
                    url = url
                };
            }

        }

        //public static string UploadToAliyun(string destFilePath, string localFilePath, OSSConfig config)
        //{
        //    OssClient ossClient = new OssClient(config.EndPoint, config.AccessKeyId, config.AccessKeySecret);
        //    return UploadToAliyun(destFilePath, localFilePath, config.OSSBucket, config.DomainUrl, ossClient);
        //}

        public async static Task<string> UploadToAliyun(string destFilePath, Stream stream, OSSConfig config, ObjectMetadata metadata = null)
        {
            OssClient ossClient = new OssClient(config.EndPoint, config.AccessKeyId, config.AccessKeySecret);
            return await UploadToAliyun(destFilePath, stream, config.OSSBucket, config.DomainUrl, ossClient, metadata);
        }

        //public static string UploadToAliyun(string destFilePath, string localFilePath, OSSConfig config, OssClient ossClient)
        //{
        //    return UploadToAliyun(destFilePath, localFilePath, config.OSSBucket, config.DomainUrl, ossClient);
        //}

        public async static Task<string> UploadToAliyun(string destFilePath, Stream stream, OSSConfig config, OssClient ossClient, ObjectMetadata metadata = null)
        {
            return await UploadToAliyun(destFilePath, stream, config.OSSBucket, config.DomainUrl, ossClient, metadata);
        }

        //public async static string UploadToAliyun(string destFilePath, string localFilePath, string ossBucket, string domainUrl, OssClient ossClient)
        //{

        //    var rst = await Task<PutObjectResult>.Factory.FromAsync(ossClient.BeginPutObject, ossClient.EndPutObject, ossBucket, localFilePath, null);

        //    var result = ossClient.PutObject(ossBucket, destFilePath, localFilePath);
        //    if (result.HttpStatusCode == System.Net.HttpStatusCode.OK)
        //    {
        //        return domainUrl + destFilePath;
        //    }
        //    else
        //    {
        //        throw new LogicalException("上传失败", ErrorCodes.UploadFileToOSSError);
        //    }
        //}

        public async static Task<string> UploadToAliyun(string destFilePath, Stream stream, string ossBucket, string domainUrl, OssClient ossClient, ObjectMetadata metadata = null)
        {
            using (stream)
            {
                stream.Position = 0;
                var tcs = new TaskCompletionSource<PutObjectResult>();
                ossClient.BeginPutObject(ossBucket, destFilePath, stream, metadata, iar =>
                {
                    tcs.SetResult(ossClient.EndPutObject(iar));
                }, null);
                var result = await tcs.Task;
                // var result = await Task<PutObjectResult>.Factory.FromAsync(ossClient.BeginPutObject, ossClient.EndPutObject, ossBucket, destFilePath, stream, null);
                if (result.ResponseStream != null)
                {
                    result.ResponseStream.Close();
                }
                if (result.HttpStatusCode == System.Net.HttpStatusCode.OK)
                {
                    return domainUrl + destFilePath;
                }
                else
                {
                    throw new LogicalException("上传失败", ErrorCodes.UploadFileToOSSError);
                }
            }
        }


        public static string GetFileIdByUrl(string url)
        {
            if (string.IsNullOrEmpty(url))
            {
                return string.Empty;
            }
            url = url.Split(new char[] { '?' })[0];
            var parts = url.Split(new string[] { "cdndev.olssglobal.com/", "olscdn.olssglobal.com/", "videodev.olssglobal.com/", "video.olssglobal.com/" }, StringSplitOptions.None);
            if (parts.Length > 1)
            {
                return parts[parts.Length - 1];
            }
            return string.Empty;
        }


        public static void RemoveFile(List<string> keys, string bucketName, OssClient ossClient)
        {
            ossClient.DeleteObjects(new DeleteObjectsRequest(bucketName, keys));
        }

    }
}
