using System;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.UI;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using YGNT.File.Core;
using YGNT.File.Core.Cache;
using YGNT.File.Core.Domain;
using YGNT.File.Core.Domain.FileFilter;

namespace YGNT.File.Application.File
{
    public class FileAppService : IFileAppService
    {
        private readonly IWebHostEnvironment _hostingEnvironment;
        private readonly IRepository<Core.File, Guid> _fileRepository;
        private readonly IFileCache _fileCache;
        private readonly IFileManager _fileManager;

        public FileAppService(IWebHostEnvironment hostingEnvironment, IRepository<Core.File, Guid> fileRepository, IFileManager fileManager, IFileCache fileCache)
        {
            _hostingEnvironment = hostingEnvironment;
            _fileRepository = fileRepository;
            _fileManager = fileManager;
            _fileCache = fileCache;
        }

        /// <summary>
        /// 上传文件(最大上传500m)
        /// </summary>
        /// <param name="formFile"></param>
        /// <param name="md5">md5值用于检测当前文件是否已经上传过(可以不传)</param>
        /// <returns></returns>
        [RequestSizeLimit(FileConst.FileSizeLimit)]
        public async Task<Guid> Upload([Required] IFormFile formFile, string md5)
        {
            if (!md5.IsNullOrEmpty())
            {
                var verifyMd5 = await _fileManager.VerifyMd5Async(md5);
                if (verifyMd5.HasValue) return (Guid)verifyMd5;
            }

            var file = await CreateFileAsync(formFile);
            //file.PhysicsPath = filePath;
            return await _fileRepository.InsertAndGetIdAsync(file);
        }




        /// <summary>
        /// 上传图片(图片最大不超过10m)
        /// </summary>
        /// <param name="formFile"></param>
        /// <param name="md5"></param>
        /// <returns></returns>
        [RequestSizeLimit(10485760)]
        public async Task<string> UploadImgAsync([Required] IFormFile formFile, string md5)
        {
            new ImageFileFilter().Filter(formFile.FileName);
            if (!md5.IsNullOrEmpty())
            {
                var verifyMd5 = await _fileManager.VerifyMd5Async(md5);
                if (verifyMd5.HasValue)
                {
                    var fileCacheItem = await _fileCache.GetAsync((Guid)verifyMd5);
                    return fileCacheItem.Path;
                }
            }
            var file = await CreateFileAsync(formFile, false);
            return file.Path;
        }

        private async Task<Core.File> CreateFileAsync(IFormFile formFile, bool randomSuffix = true)
        {
            var file = new Core.File()
            {
                FileName = Path.GetFileNameWithoutExtension(formFile.FileName),
                Suffix = Path.GetExtension(formFile.FileName),
                Size = formFile.Length,
            };

            var filePath = Path.Combine(_hostingEnvironment.GetFilesPath(), DateTime.Today.ToString("yyyy-MMMM-dd"));
            if (!Directory.Exists(filePath)) Directory.CreateDirectory(filePath);
            filePath = Path.Combine(filePath, Path.GetRandomFileName());
            if (!randomSuffix)
                filePath = Path.ChangeExtension(filePath, file.Suffix);
            await using (var addFile = new FileStream(filePath, FileMode.OpenOrCreate))
            {
                await formFile.CopyToAsync(addFile);
                addFile.Seek(0, SeekOrigin.Begin);
                //获取md5值
                System.Security.Cryptography.MD5 md5Crypto = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] retVal = md5Crypto.ComputeHash(addFile);
                StringBuilder sb = new StringBuilder();
                foreach (var t in retVal)
                {
                    sb.Append(t.ToString("x2"));
                }

                file.Md5 = sb.ToString();
            }
            file.Path = Path.GetRelativePath(_hostingEnvironment.WebRootPath, filePath);
            return file;
        }

        /// <summary>
        /// 读取文件
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<object> ReadFile([Required] Guid id)
        {
            var file = await _fileRepository.GetAsync(id);
            var filePath = Path.Combine(_hostingEnvironment.WebRootPath, file.Path);
            if (!System.IO.File.Exists(filePath))
                throw new UserFriendlyException("文件不存在!");
            var fileBytes = await System.IO.File.ReadAllBytesAsync(filePath);
            return new FileContentResult(fileBytes, GetContextType(file.Suffix))
            {
                FileDownloadName = file.FileName + file.Suffix,
            };
        }

        private string GetContextType(string suffix)
        {
            //获取文件的ContentType
            var provider = new FileExtensionContentTypeProvider();
            provider.TryGetContentType(suffix, out var contentType);
            if (contentType.IsNullOrEmpty()) contentType = "application/octet-stream";
            return contentType;
        }

    }
}