namespace Hims.Infrastructure.Helpers
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Runtime.CompilerServices;
    using System.Threading.Tasks;
    using Amazon;
    using Amazon.S3;
    using Amazon.S3.Model;
    using Amazon.S3.Transfer;
    using Domain.Configurations;
    using Domain.Helpers;
    using LazZiya.ImageResize;
    using Microsoft.AspNetCore.Http;
    using Org.BouncyCastle.Asn1.X509;
    using Shared.DataFilters;
    using Domain.Repositories.UnitOfWork;
    using Hims.Shared.UserModels.Slots;
    using Hims.Domain.Entities;
    using Hims.Shared.Library;
    using Microsoft.AspNetCore.Hosting.Server;

    /// <inheritdoc />
    public class DocumentHelper : IDocumentHelper
    {
        /// <summary>
        /// The configuration.
        /// </summary>
        private readonly IAmazonS3Configuration configuration;

       
        /// <summary>
        /// The ftp configuration.
        /// </summary>
        private readonly INewFtpConfiguration newftpConfiguration;

        /// <summary>
        /// the unit of work
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

        /// <inheritdoc cref="IDocumentHelper" />
        public DocumentHelper(IAmazonS3Configuration configuration, INewFtpConfiguration NewftpConfiguration, IUnitOfWork unitOfWork)
        {
            this.configuration = configuration;
            
            this.newftpConfiguration = NewftpConfiguration;
            this.unitOfWork = unitOfWork;
        }

        /// <inheritdoc />
        public string GetUrl(Guid guid, string fileName) => this.configuration.BucketURL + guid + "/" + fileName;

        /// <inheritdoc />
        public string GetDbUrl(Guid guid, string fileName) => fileName.Replace(this.configuration.BucketURL + guid + "/", string.Empty);

        /// <inheritdoc />
        public async Task<bool> DeleteAsync(Guid guid, string fileUrl)
        {
            var region = RegionEndpoint.GetBySystemName(this.configuration.Region);
            var client = new AmazonS3Client(this.configuration.AccessKey, this.configuration.SecretKey, region);

            var request = new DeleteObjectRequest
            {
                BucketName = this.configuration.BucketName,
                Key = guid + "/" + fileUrl
            };

            var response = await client.DeleteObjectAsync(request);
            return response.HttpStatusCode == HttpStatusCode.OK;
        }

        /// <inheritdoc />
        public async Task<string> UploadAsync(IFormFile fileInfo, Guid guid, string folderName, string filName)
        {
            var fileUrl = $"{folderName}/{filName}";

            //var ftp = FtpTransfer(filName, fileInfo);
            var region = RegionEndpoint.GetBySystemName(this.configuration.Region);
            var client = new AmazonS3Client(this.configuration.AccessKey, this.configuration.SecretKey, region);
            var fileTransferUtility = new TransferUtility(client);

            var request = new TransferUtilityUploadRequest
            {
                InputStream = fileInfo.OpenReadStream(),
                BucketName = this.configuration.BucketName,
                CannedACL = S3CannedACL.PublicRead,
                //Key = "PaymentDocuments" + "/Payment/" + fileUrl
                Key = guid + "/" + fileUrl
            };
            await fileTransferUtility.UploadAsync(request);

            return fileUrl;
        }

        /// <inheritdoc />
        public async Task<string> UploadProfileImageAsync(IFormFile fileInfo, Guid guid, string folderName, string filName)
        {
            var fileUrl = $"{folderName}/{filName}";
            var region = RegionEndpoint.GetBySystemName(this.configuration.Region);
            var client = new AmazonS3Client(this.configuration.AccessKey, this.configuration.SecretKey, region);
            var fileTransferUtility = new TransferUtility(client);

            var request = new TransferUtilityUploadRequest
            {
                InputStream = fileInfo.OpenReadStream(),
                BucketName = this.configuration.BucketName,
                CannedACL = S3CannedACL.PublicRead,
                //Key = "PaymentDocuments" + "/Payment/" + fileUrl
                Key = guid + "/" + fileUrl
            };
            await fileTransferUtility.UploadAsync(request);

            return fileUrl;
        }

        /// <inheritdoc />
        public async Task<string> UploadThumbnailImageAsync(IFormFile fileInfo, Guid guid, string folderName, string filName)
        {
            var fileUrl = $"{folderName}/{filName}";
            var region = RegionEndpoint.GetBySystemName(this.configuration.Region);
            var client = new AmazonS3Client(this.configuration.AccessKey, this.configuration.SecretKey, region);
            var fileTransferUtility = new TransferUtility(client);

            var request = new TransferUtilityUploadRequest
            {
                InputStream = fileInfo.OpenReadStream(),
                BucketName = this.configuration.BucketName,
                CannedACL = S3CannedACL.PublicRead,
                //Key = "PaymentDocuments" + "/Payment/" + fileUrl
                Key = guid + "/" + fileUrl
            };
            await fileTransferUtility.UploadAsync(request);

            return fileUrl;
        }

        /// <inheritdoc />
        public async Task<string> UploadThumbnailAsync(IFormFile fileInfo, Guid guid, string folderName, string filName)
        {
            var fileUrl = $"{folderName}/Thumbnails/{filName}";
            var region = RegionEndpoint.GetBySystemName(this.configuration.Region);
            var client = new AmazonS3Client(this.configuration.AccessKey, this.configuration.SecretKey, region);
            var fileTransferUtility = new TransferUtility(client);

            var request = new TransferUtilityUploadRequest
            {
                InputStream = fileInfo.OpenReadStream(),
                BucketName = this.configuration.BucketName,
                CannedACL = S3CannedACL.PublicRead,
                Key = guid + "/" + fileUrl
            };
            await fileTransferUtility.UploadAsync(request);

            return this.GetThumbnail(fileInfo.ContentType);
        }

        /// <inheritdoc />
        public async Task<string> UploadAttachmentsAsync(IFormFile fileInfo, string basePath, string folderName, string filName)
        {
            var fileUrl = $"{folderName}/{filName}";
            var region = RegionEndpoint.GetBySystemName(this.configuration.Region);
            var client = new AmazonS3Client(this.configuration.AccessKey, this.configuration.SecretKey, region);
            var fileTransferUtility = new TransferUtility(client);

            var request = new TransferUtilityUploadRequest
            {
                InputStream = fileInfo.OpenReadStream(),
                BucketName = this.configuration.BucketName,
                CannedACL = S3CannedACL.PublicRead,
                Key = basePath + "/" + fileUrl
            };
            await fileTransferUtility.UploadAsync(request);

            return fileUrl;
        }

        /// <inheritdoc />
        public async Task<string> UploadImageAsync(string base64Image, string basePath, string folderName, string filName)
        {
            var region = RegionEndpoint.GetBySystemName(this.configuration.Region);
            var client = new AmazonS3Client(this.configuration.AccessKey, this.configuration.SecretKey, region);
            var profileImageUrl = $"{basePath}/{folderName}/{filName}.jpg";
            // Actual File
            var imageBytes = CoreFilter.ToImageBytes(base64Image);
            var imageStream = new MemoryStream(imageBytes);
            var request = new PutObjectRequest
            {
                BucketName = this.configuration.BucketName,
                CannedACL = S3CannedACL.PublicRead,
                Key = profileImageUrl,
                InputStream = imageStream
            };

            await client.PutObjectAsync(request);

            return profileImageUrl;
        }

        /// <inheritdoc />
        public async Task<Tuple<string, string>> UploadAsync(string base64Image, Guid guid, string folderName, string filName)
        {
            try
            {
                if (!string.IsNullOrEmpty(base64Image))
                {
                    var region = RegionEndpoint.GetBySystemName(this.configuration.Region);
                    var client = new AmazonS3Client(this.configuration.AccessKey, this.configuration.SecretKey, region);

                    var deleteRequest = new DeleteObjectsRequest
                    {
                        BucketName = this.configuration.BucketName,
                    };

                    var listRequest = new ListObjectsRequest
                    {
                        BucketName = this.configuration.BucketName,
                        Prefix = guid + "/Profile"
                    };

                    var listResponse = await client.ListObjectsAsync(listRequest);
                    foreach (var entry in listResponse.S3Objects)
                    {
                        deleteRequest.AddKey(entry.Key);
                    }

                    if (listResponse.S3Objects.Count > 0)
                    {
                        await client.DeleteObjectsAsync(deleteRequest);
                    }

                    var profileImageUrl = $"{folderName}/{filName}.jpg";
                    var thumbnailUrl = $"{folderName}/Thumbnail/{filName}.jpg";

                    // Actual File
                    var imageBytes = CoreFilter.ToImageBytes(base64Image);
                    var imageStream = new MemoryStream(imageBytes);
                    var request = new PutObjectRequest
                    {
                        BucketName = this.configuration.BucketName,
                        CannedACL = S3CannedACL.PublicRead,
                        Key = guid + "/" + profileImageUrl,
                        InputStream = imageStream
                    };

                    // await client.PutObjectAsync(request);

                    // Thumbnail
                    var ms = new MemoryStream(imageBytes);
                    var image = new Bitmap(ms);
                    var thumbnail = image.Scale(128, 128);
                    var thumbnailStream = new MemoryStream();
                    thumbnail.Save(thumbnailStream, image.RawFormat);
                    var thumbnailRequest = new PutObjectRequest
                    {
                        BucketName = this.configuration.BucketName,
                        CannedACL = S3CannedACL.PublicRead,
                        Key = guid + "/" + thumbnailUrl,
                        InputStream = thumbnailStream
                    };

                    await client.PutObjectAsync(thumbnailRequest);
                    // vikas said to upload only thumbnail.
                    // return new Tuple<string, string>(profileImageUrl, thumbnailUrl);
                    return new Tuple<string, string>(thumbnailUrl, thumbnailUrl);
                }

                return new Tuple<string, string>(null, null);
            }
            catch (Exception e)
            {

            }
            return null;
        }

        /// <inheritdoc />
        public async Task<string> UploadProfileImageAsync(string base64Image, Guid guid, string folderName, string filName)
        {
            if (!string.IsNullOrEmpty(base64Image))
            {
                var region = RegionEndpoint.GetBySystemName(this.configuration.Region);
                var client = new AmazonS3Client(this.configuration.AccessKey, this.configuration.SecretKey, region);

                var deleteRequest = new DeleteObjectsRequest
                {
                    BucketName = this.configuration.BucketName,
                };

                var listRequest = new ListObjectsRequest
                {
                    BucketName = this.configuration.BucketName,
                    Prefix = guid + "/Profile"
                };

                var listResponse = await client.ListObjectsAsync(listRequest);
                foreach (var entry in listResponse.S3Objects)
                {
                    deleteRequest.AddKey(entry.Key);
                }

                if (listResponse.S3Objects.Count > 0)
                {
                    await client.DeleteObjectsAsync(deleteRequest);
                }

                var profileImageUrl = $"{folderName}/{filName}.jpg";
                // var thumbnailUrl = $"{folderName}/Thumbnail/{filName}.jpg";

                // Actual File
                var imageBytes = CoreFilter.ToImageBytes(base64Image);
                var imageStream = new MemoryStream(imageBytes);
                var request = new PutObjectRequest
                {
                    BucketName = this.configuration.BucketName,
                    CannedACL = S3CannedACL.PublicRead,
                    Key = guid + "/" + profileImageUrl,
                    InputStream = imageStream
                };

                await client.PutObjectAsync(request);

                return profileImageUrl;
            }

            return null;
        }

        /// <inheritdoc />
        public async Task<string> UploadThumbnailImageAsync(string base64ThumnailImage, Guid guid, string folderName, string filName)
        {
            if (!string.IsNullOrEmpty(base64ThumnailImage))
            {
                var region = RegionEndpoint.GetBySystemName(this.configuration.Region);
                var client = new AmazonS3Client(this.configuration.AccessKey, this.configuration.SecretKey, region);

                var deleteRequest = new DeleteObjectsRequest
                {
                    BucketName = this.configuration.BucketName,
                };

                var listRequest = new ListObjectsRequest
                {
                    BucketName = this.configuration.BucketName,
                    Prefix = guid + "/Thumbnail"
                };

                var listResponse = await client.ListObjectsAsync(listRequest);
                foreach (var entry in listResponse.S3Objects)
                {
                    deleteRequest.AddKey(entry.Key);
                }

                if (listResponse.S3Objects.Count > 0)
                {
                    await client.DeleteObjectsAsync(deleteRequest);
                }

                // var profileImageUrl = $"{folderName}/{filName}.jpg";
                var thumbnailUrl = $"{folderName}/{filName}.jpg";

                // Actual File
                var imageBytes = CoreFilter.ToImageBytes(base64ThumnailImage);
                var imageStream = new MemoryStream(imageBytes);
                var request = new PutObjectRequest
                {
                    BucketName = this.configuration.BucketName,
                    CannedACL = S3CannedACL.PublicRead,
                    Key = guid + "/" + thumbnailUrl,
                    InputStream = imageStream
                };

                await client.PutObjectAsync(request);

                return thumbnailUrl;
            }

            return null;
        }

        /// <inheritdoc />
        public async Task<string> UploadEncounterImagesAsync(string base64Image, Guid guid, string folderName, string filName)
        {
            if (string.IsNullOrEmpty(base64Image))
            {
                return null;
            }

            var region = RegionEndpoint.GetBySystemName(this.configuration.Region);
            var client = new AmazonS3Client(this.configuration.AccessKey, this.configuration.SecretKey, region);

            var imageUrl = $"{folderName}/{filName}.jpg";

            // Actual File
            var imageBytes = CoreFilter.ToImageBytes(base64Image);
            var imageStream = new MemoryStream(imageBytes);
            var request = new PutObjectRequest
            {
                BucketName = this.configuration.BucketName,
                CannedACL = S3CannedACL.PublicRead,
                Key = guid + "/" + imageUrl,
                InputStream = imageStream
            };

            await client.PutObjectAsync(request);

            return this.GetUrl(guid, imageUrl);
        }

        /// <inheritdoc />
        public IEnumerable<string> FetchContentTypes()
        {
            return new[] { "application/pdf", "image/jpeg", "image/pjpeg", "image/png", "image/gif", "video/mp4" };
        }

        /// <inheritdoc />
        public IEnumerable<string> FetchImageContentTypes()
        {
            return new[] { "image/jpeg", "image/pjpeg", "image/png", "image/gif" };
        }

        /// <inheritdoc />
        public string GetThumbnail(string contentType)
        {
            // var docTypes = new[] { "application/doc", "application/ms-doc", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" };
            // var excelTypes = new[] { "application/excel", "application/vnd.ms-excel", "application/x-excel", "application/x-msexcel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" };
            var pdfTypes = new[] { "application/pdf" };

            // var odtTypes = new[] { "application/odt" };
            // var rtfTypes = new[] { "application/rtf" };
            // var txtTypes = new[] { "text/plain" };
            var jpgTypes = new[] { "image/jpeg", "image/pjpeg" };
            var pngTypes = new[] { "image/png" };
            var gifTypes = new[] { "image/gif" };
            var mp4Types = new[] { "video/mp4" };
            var aviTypes = new[] { "video/avi" };
            var gpTypes = new[] { "video/3gpp" };
            var flvTypes = new[] { "video/flv" };
            var mpgTypes = new[] { "video/mpg" };
            var ogvTypes = new[] { "video/ogv" };

            // if (docTypes.Contains(contentType))
            // {
            // return "public/doc.png";
            // }
            // if (excelTypes.Contains(contentType))
            // {
            // return "public/excel.png";
            // }
            if (pdfTypes.Contains(contentType))
            {
                return "public/pdf.png";
            }

            // if (odtTypes.Contains(contentType))
            // {
            // return "public/otf.png";
            // }
            // if (rtfTypes.Contains(contentType))
            // {
            // return "public/rtf.png";
            // }
            // if (txtTypes.Contains(contentType))
            // {
            // return "public/txt.png";
            // }
            if (jpgTypes.Contains(contentType))
            {
                return "public/jpg.png";
            }

            if (pngTypes.Contains(contentType))
            {
                return "public/png.png";
            }

            if (gifTypes.Contains(contentType))
            {
                return "public/gif.png";
            }

            if (mp4Types.Contains(contentType))
            {
                return "public/mp4.png";
            }

            if (aviTypes.Contains(contentType))
            {
                return "public/avi.png";
            }

            if (gpTypes.Contains(contentType))
            {
                return "public/3gp.png";
            }

            if (flvTypes.Contains(contentType))
            {
                return "public/flv.png";
            }

            if (mpgTypes.Contains(contentType))
            {
                return "public/mpg.png";
            }

            if (ogvTypes.Contains(contentType))
            {
                return "public/ogv.png";
            }

            return "public/other.png";
        }

        /// <summary>
        /// The upload document async.
        /// </summary>
        /// <param name="fileInfo">
        /// The file info.
        /// </param>
        /// <param name="guid">
        /// The guid.
        /// </param>
        /// <param name="folderName">
        /// The folder name.
        /// </param>
        /// <param name="filName">
        /// The fil name.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public async Task<string> UploadDocumentAsync(IFormFile fileInfo, Guid guid, string folderName, string filName)
        {
            var fileUrl = $"{folderName}/{filName}";
            var region = RegionEndpoint.GetBySystemName(this.configuration.Region);
            var client = new AmazonS3Client(this.configuration.AccessKey, this.configuration.SecretKey, region);
            var fileTransferUtility = new TransferUtility(client);

            var request = new TransferUtilityUploadRequest
            {
                InputStream = fileInfo.OpenReadStream(),
                BucketName = this.configuration.BucketName,
                CannedACL = S3CannedACL.PublicRead,
                Key = "PaymentDocuments" + "/Payment/" + fileUrl
            };
            await fileTransferUtility.UploadAsync(request);

            return fileUrl;
        }

        /// <summary>
        /// The delete attachments async.
        /// </summary>
        /// <param name="fileUrl">
        /// The file url.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public async Task<bool> DeleteAttachmentsAsync(string fileUrl)
        {
            var region = RegionEndpoint.GetBySystemName(this.configuration.Region);
            var client = new AmazonS3Client(this.configuration.AccessKey, this.configuration.SecretKey, region);

            var request = new DeleteObjectRequest
            {
                BucketName = this.configuration.BucketName,
                Key = fileUrl
            };

            var response = await client.DeleteObjectAsync(request);
            return response.HttpStatusCode == HttpStatusCode.OK;
        }
    }
}