using Amazon.S3;
using Amazon.S3.Model;
using Amazon.S3.Transfer;
using Marco.Pms.Model.Utilities;
using MarcoBMS.Services.Service;
using Microsoft.Extensions.Options;
using MimeDetective;
using System.Text.RegularExpressions;

namespace Marco.Pms.Services.Service
{

    public class S3UploadService
    {
        private readonly IAmazonS3 _s3Client;
        private readonly string _bucketName;
        private readonly ILoggingService _logger;
        private readonly IConfiguration _configuration;

        public S3UploadService(IOptions<AWSSettings> awsOptions, ILoggingService logger, IConfiguration configuration)
        {
            _logger = logger;
            _configuration = configuration;
            var settings = awsOptions.Value;

            var region = Amazon.RegionEndpoint.GetBySystemName(settings.Region);
            _bucketName = settings.BucketName;

            _s3Client = new AmazonS3Client(settings.AccessKey, settings.SecretKey, region);
        }
        //public async Task<string> UploadFileAsync(string fileName, string contentType)
        public async Task UploadFileAsync(string base64, string fileType, string objectKey)
        {
            byte[] fileBytes;


            var allowedFilesType = _configuration.GetSection("WhiteList:ContentType")
                                                .GetChildren()
                                                .Select(x => x.Value)
                                                .ToList();

            if (allowedFilesType == null || !allowedFilesType.Contains(fileType))
            {
                _logger.LogWarning("Unsupported file type. {FileType}", fileType);
                //throw new InvalidOperationException("Unsupported file type.");
                return;
            }

            fileBytes = Convert.FromBase64String(base64);


            using var fileStream = new MemoryStream(fileBytes);

            var uploadRequest = new TransferUtilityUploadRequest
            {
                InputStream = fileStream,
                Key = objectKey,
                BucketName = _bucketName,
                ContentType = fileType,
                AutoCloseStream = true
            };
            try
            {
                var transferUtility = new TransferUtility(_s3Client);
                await transferUtility.UploadAsync(uploadRequest);
                _logger.LogInfo("File uploaded to Amazon S3");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error ocurred while uploading file to S3", ex.Message);
            }


        }
        public string GeneratePreSignedUrl(string objectKey)
        {

            int expiresInMinutes = 10;
            var request = new GetPreSignedUrlRequest
            {
                BucketName = _bucketName,
                Key = objectKey,
                Expires = DateTime.UtcNow.AddMinutes(expiresInMinutes),
                Verb = HttpVerb.GET // for download
            };
            try
            {
                string url = _s3Client.GetPreSignedURL(request);
                _logger.LogInfo("Requested presigned url from Amazon S3");
                return url;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error occured while requesting presigned url from Amazon S3");
                return string.Empty;
            }
        }
        public async Task<bool> DeleteFileAsync(string objectKey)
        {
            try
            {
                var deleteRequest = new DeleteObjectRequest
                {
                    BucketName = _bucketName,
                    Key = objectKey
                };

                var response = await _s3Client.DeleteObjectAsync(deleteRequest);
                _logger.LogInfo("File deleted from Amazon S3");
                return response.HttpStatusCode == System.Net.HttpStatusCode.NoContent;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "while deleting from Amazon S3");
                return false;
            }
        }
        public string GenerateFileName(string contentType, Guid entityId, string? name)
        {
            string extenstion = GetExtensionFromMimeType(contentType);

            if (string.IsNullOrEmpty(name))
                return $"{entityId}_{DateTime.UtcNow:yyyyMMddHHmmssfff}{extenstion}";
            return $"{name}_{entityId}_{DateTime.UtcNow:yyyyMMddHHmmssfff}{extenstion}";

        }
        public string GetExtensionFromMimeType(string contentType)
        {
            switch (contentType.ToLowerInvariant())
            {
                case "application/pdf":
                    return ".pdf";

                case "application/msword":
                    return ".doc";

                case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
                    return ".docx";

                case "application/vnd.ms-excel":
                    return ".xls";

                case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
                    return ".xlsx";

                case "application/mspowerpoint":
                    return ".ppt";

                case "application/vnd.openxmlformats-officedocument.presentationml.presentation":
                    return ".pptx";

                case "text/plain":
                    return ".txt";

                case "application/rtf":
                    return ".rtf";

                case "image/jpeg":
                    return ".jpg";

                case "image/png":
                    return ".png";

                case "image/gif":
                    return ".gif";

                case "image/bmp":
                    return ".bmp";

                case "text/csv":
                    return ".csv";

                default:
                    return ""; // or ".bin", or throw an error, based on your needs
            }
        }
        public string GetContentTypeFromBase64(string base64String)
        {
            if (string.IsNullOrEmpty(base64String))
            {
                return string.Empty; // Or handle the empty case as needed
            }

            try
            {
                // 1. Decode the Base64 string to a byte array
                byte[] decodedBytes = Convert.FromBase64String(base64String);

                // 2. Create a ContentInspector (using default definitions for this example)
                var inspector = new ContentInspectorBuilder()
                {
                    Definitions = MimeDetective.Definitions.DefaultDefinitions.All()
                }.Build();

                // 3. Inspect the byte array to determine the content type
                var results = inspector.Inspect(decodedBytes);

                if (results.Any())
                {
                    var bestMatch = results
                        .OrderByDescending(r => r.Points)
                        .FirstOrDefault();
                    if (bestMatch?.Definition?.File?.MimeType != null)
                    {
                        return bestMatch.Definition.File.MimeType;
                    }
                    else
                    {
                        _logger.LogWarning("Warning: Could not find MimeType, Type, or ContentType property in Definition.");
                        return "application/octet-stream";
                    }
                }
                else
                {
                    return "application/octet-stream"; // Default if type cannot be determined
                }
            }
            catch (FormatException fEx)
            {
                // Handle cases where the input string is not valid Base64
                _logger.LogError(fEx, "Invalid Base64 string.");
                return string.Empty;
            }
            catch (Exception ex)
            {
                // Handle other potential errors during decoding or inspection
                _logger.LogError(ex, "An error occurred while decoding base64");
                return string.Empty;
            }
        }
        public bool IsBase64String(string? input)
        {
            if (string.IsNullOrWhiteSpace(input))
                return false;

            // Normalize string
            input = input.Trim();

            // Length must be multiple of 4
            if (input.Length % 4 != 0)
                return false;

            // Valid Base64 characters with correct padding
            var base64Regex = new Regex(@"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$");
            if (!base64Regex.IsMatch(input))
                return false;

            try
            {
                // Decode and re-encode to confirm validity
                var bytes = Convert.FromBase64String(input);
                var reEncoded = Convert.ToBase64String(bytes);
                return input == reEncoded;
            }
            catch
            {
                return false;
            }
        }
    }
}