using ImageMagick;
using Lada.Framework.Data.Enums;
using Lada.Framework.DTO;
using Lada.Framework.DTO.Results.Media;
using Lada.Framework.Infrastructures.AppSettings;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;

namespace Lada.Framework.Infrastructures.Services
{
    public interface IPictureService
    {
        Task<UploadPictureResult> Upload(IFormFile file,PictureType pictureType);
    }



    public class PictureService : IPictureService
    {
        private MediaSettings _mediaSettings;
        public PictureService(IOptions<MediaSettings> mediaSettings)
        {
            _mediaSettings = mediaSettings.Value;
        }

        public async Task<UploadPictureResult> Upload(IFormFile file, PictureType pictureType)
        {
            var result = new UploadPictureResult();

            #region Lưu file gốc
            var originalFolderName = OriginalFolderPath(pictureType);
            var originalFileExt = Path.GetExtension(file.FileName).ToLower();
            var originalFileName = OriginalFileName(file);
            var savedOriginalFilePath = await SaveToDisk(file, originalFileName, originalFolderName); 
            #endregion

            var validFile = ValidatePicture(savedOriginalFilePath);


            if (string.IsNullOrEmpty(validFile))
            {
                result.Result = Result.Failed;
                result.Message = "File tải lên không hợp lệ";
            }
            else
            {
                var imageFormat = MagickFormat.Jpg;
                switch (_mediaSettings.ImageFormat)
                {
                    case 1:
                        imageFormat = MagickFormat.Jpg;break;
                    case 2:
                        imageFormat = MagickFormat.WebP;break;
                    case 3:
                        imageFormat = MagickFormat.Avif;break;
                    default:
                        break;
                }
                var resizedFilePath = Resize(savedOriginalFilePath, imageFormat);
                var path = resizedFilePath.Replace($"{_mediaSettings.Drive + _mediaSettings.RootPath}", _mediaSettings.ImageDomain);
                result.Url = (new Uri(path)).AbsoluteUri;
            }
            RemoveOriginalFile(savedOriginalFilePath);
            return result;
        }


        #region Utilities

        #region File gốc
        private string OriginalFolderPath(PictureType pictureType)
        {
            var picType = Enum.GetName(pictureType);
            var result = $"Pictures\\{picType}\\{DateTimeOffset.Now.Year}\\{DateTimeOffset.Now.Month}\\{DateTimeOffset.Now.Day}\\";
            return result;
        }

        private string OriginalFileName(IFormFile file)
        {
            var fileNamewithouExt = Path.GetFileNameWithoutExtension(file.FileName);
            var fileExt = Path.GetExtension(file.FileName).ToLower();
            var fileName = fileNamewithouExt.Length <= 90 ? fileNamewithouExt : fileNamewithouExt.Substring(0, 90);
            var result = $"{fileName}-{DateTimeOffset.Now.Ticks}{fileExt}";
            return result;
        } 

        private void RemoveOriginalFile(string path)
        {
            try
            {
                // Kiểm tra xem file có tồn tại không
                if (File.Exists(path))
                {
                    // Xóa file
                    File.Delete(path);
                    
                }
                
            }
            catch (Exception)
            {
                
            }
        }
        #endregion


        private async Task<string> SaveToDisk(IFormFile file, string fileName, string relativeFolder)
        {

            var fullFolderPath = _mediaSettings.Drive + _mediaSettings.RootPath + relativeFolder;
            var filePath = fullFolderPath + fileName;
            if (!Directory.Exists(fullFolderPath))
            {
                Directory.CreateDirectory(fullFolderPath);
            }
            var fileInfo = new FileInfo(filePath);
            if (fileInfo.Exists)
            {
                fileInfo.Delete();
            }
            using (var fileStream = new FileStream(filePath, FileMode.Create))
            {
                await file.CopyToAsync(fileStream);
            }
            return filePath;
        }

        private string ValidatePicture(string fullFilePath)
        {
            var localFileStream = new FileStream(fullFilePath, FileMode.Open);
            byte[] headerBytes = new byte[4];
            localFileStream.Read(headerBytes, 0, 4);
            localFileStream.Close();
            var isValidImage = ValidatePictureFile(headerBytes, localFileStream.Name);
            if (!isValidImage)
            {
                var efile = new FileInfo(fullFilePath);
                efile.Delete();
                return "";
            }
            return fullFilePath;
        }
        private static bool CompareArray(byte[] a1, byte[] a2)
        {
            if (a1.Length != a2.Length)
                return false;

            for (int i = 0; i < a1.Length; i++)
            {
                if (a1[i] != a2[i])
                    return false;
            }

            return true;
        }

        private bool ValidatePictureFile(byte[] fileHeaders, string filename)
        {
            var imageHeader = new Dictionary<string, byte[]>
            {
                {"JPG", new byte[] {0xFF, 0xD8, 0xFF}},
                {"JPEG", new byte[] {0xFF, 0xD8, 0xFF}},
                {"PNG", new byte[] {0x89, 0x50, 0x4E, 0x47}},
                {"TIF", new byte[] {0x49, 0x49, 0x2A, 0x00}},
                {"TIFF", new byte[] {0x49, 0x49, 0x2A, 0x00}},
                {"GIF", new byte[] {0x47, 0x49, 0x46, 0x38}},
                {"BMP", new byte[] {0x42, 0x4D}},
                {"ICO", new byte[] {0x00, 0x00, 0x01, 0x00}}
            };
            var fileExt = filename.Substring(filename.LastIndexOf('.') + 1).ToUpper();

            try
            {
                var rs = false;
                var tmp = imageHeader[fileExt];
                if (fileExt == "JPG" || fileExt == "JPEG")
                {
                    fileHeaders = fileHeaders.Take(3).ToArray();
                }
                rs = CompareArray(tmp, fileHeaders);
                if (!rs)
                {
                    if (fileExt == "JPG" || fileExt == "JPEG")
                    {
                        var tmp2 = imageHeader["PNG"].Take(3).ToArray();
                        rs = CompareArray(tmp2, fileHeaders);
                    }
                }
                return rs;
            }
            catch (Exception)
            {
                return false;
            }
        }


        /// <summary>
        /// Resize kích thước ảnh
        /// </summary>
        /// <param name="imagePath"></param>
        /// <param name="outputFolder"></param>
        /// <returns></returns>
        public string Resize(string imagePath, MagickFormat format)
        {
            var fileInfo = new FileInfo(imagePath);
            var outputFolder = $"{fileInfo.Directory.FullName}\\{_mediaSettings.OutputFolder}";
            var fileName = Path.GetFileNameWithoutExtension(imagePath);
            if (!Directory.Exists(outputFolder))
            {
                Directory.CreateDirectory(outputFolder);
            }

            var outputFileInfo = new FileInfo($"{outputFolder}\\{fileName}.{format.ToString().ToLower()}");
            if (outputFileInfo.Exists)
            {
                outputFileInfo.Delete();
            }

            using (MagickImage image = new MagickImage(fileInfo))
            {
                var currentWidth = image.Page.Width;
                var maxWidth = (uint)_mediaSettings.MaxWidth;
                image.Quality = 80;
                //image.Settings.SetDefine(format, "lossless", false);
                //image.Resize(currentWidth > maxWidth ? maxWidth : currentWidth, currentWidth > maxWidth ? maxWidth : currentWidth);
                var geometry = new MagickGeometry();
                geometry.Width = currentWidth > maxWidth ? maxWidth : currentWidth;
                image.Resize(geometry);
                image.Write(outputFileInfo);
            }
            return outputFileInfo.FullName;
        }
        #endregion
    }
}
