using System;
using System.ComponentModel;
using System.IO;
using System.Security.Claims;
using System.Threading.Tasks;
using AutoMapper;
using Azure.Core;
using Domain.Identity;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Services.Identity;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Processing;
using Image = SixLabors.ImageSharp.Image;

namespace Api.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    [EnableCors("AllowAll")]
    public class BaseController : ControllerBase
    {
        private readonly AutoMapper.IMapper _mapper;
        private readonly IWebHostEnvironment _environment;
        private readonly IAuthService authService;
        private readonly IServiceProvider serviceProvider;
        //response messages


        public BaseController(IServiceProvider serviceProvider)
        {
            _mapper = serviceProvider.GetService<IMapper>();
            _environment = serviceProvider.GetService<IWebHostEnvironment>();
            authService = serviceProvider.GetService<IAuthService>();
        }


        public IMapper Mapper => _mapper;
        private T GetClaim<T>(string type)
        {
            var value = User.FindFirstValue(type) ?? "";

            var converter = TypeDescriptor.GetConverter(typeof(T));

            try
            {
                return (T)converter.ConvertFromString(value);
            }
            catch
            {
                return default;
            }


        }
        private Account _currentAccount;
        public Account CurrentAccount
        {
            get
            {
                if (_currentAccount == null)
                    _currentAccount = authService.GetByUsername(CurrentClaim.Username);
                return _currentAccount;
            }
        }
        private CustomUser GetUser()
        {
            return new CustomUser
            {
                Id = GetClaim<Guid>(ITokenIssuer.Claims.Id),
                Name = GetClaim<string>(ITokenIssuer.Claims.Name),
                Username = GetClaim<string>(ITokenIssuer.Claims.Username),
                Roles = GetClaim<string>(ClaimTypes.Role).Split(',')
            };
        }
        public CustomUser CurrentClaim => GetUser();

        /// <summary>
        /// get images as byte array and returns maximun 1000 pixle base64
        /// </summary>
        /// <param name="inStream"></param>
        /// <returns></returns>
        [ApiExplorerSettings(IgnoreApi = true)]
        public byte[] ResizeImage(byte[] inStream, int maxWidth = 1000)
        {
            using (var ms = new MemoryStream())
            {
                using (Image image = Image.Load(inStream))
                {
                    if (image.Width < maxWidth)
                    {
                        image.SaveAsPng(ms);
                        return ms.ToArray();
                    }
                    var ratio = (double)(maxWidth) / image.Width;
                    int width = image.Width;
                    int height = (int)(image.Height * ratio);
                    image.Mutate(x => x.Resize(width, height));

                    image.SaveAsPng(ms);
                    return ms.ToArray();
                }
            }
        }


        [ApiExplorerSettings(IgnoreApi = true)]
        private string GetUniqueFileName(string fileName)
        {
            fileName = Path.GetFileName(fileName);
            return string.Concat(Path.GetFileNameWithoutExtension(fileName)
                                , "_"
                                , Guid.NewGuid().ToString().AsSpan(0, 4)
                                , Path.GetExtension(fileName));
        }
        /// <summary>
        /// Saves base64 as a PNG with max 1500px width or height
        /// </summary>
        /// <param name="fileContent">base64 image</param>
        /// <param name="fileName">New file=empty</param>
        /// <returns>File Name(all of files stores in UploadedFiles folder </returns>
        [ApiExplorerSettings(IgnoreApi = true)]
        protected string SaveImageFromBase64(string fileContent, string fileName = "")
        {
            fileName = string.IsNullOrEmpty(fileName) ? Guid.NewGuid().ToString() + ".png" : fileName;
            string outputPath = $"{_environment.ContentRootPath}\\UploadedFiles\\";
            if (!System.IO.Directory.Exists(outputPath))
                System.IO.Directory.CreateDirectory(outputPath);
            // Decode Base64 string to byte array
            byte[] imageBytes = Convert.FromBase64String(fileContent);

            using (MemoryStream ms = new MemoryStream(imageBytes))
            using (Image image = Image.Load(ms))
            {
                // Resize if width > 1500, keeping aspect ratio
                if (image.Width >= image.Height)
                {
                    if (image.Width > 1500)
                    {
                        int newWidth = 1500;
                        int newHeight = (int)((double)newWidth / image.Width * image.Height);

                        image.Mutate(x => x.Resize(newWidth, newHeight));
                    }
                }
                else
                {
                    if (image.Height > 1500)
                    {
                        int newHeight = 1500;
                        int newWidth = (int)((double)newHeight / image.Height * image.Width);
                        image.Mutate(x => x.Resize(newWidth, newHeight));
                    }
                }
                // Save as PNG                
                image.Save($"{outputPath}{fileName}", new PngEncoder());
                return fileName;
            }
        }
    }

    public class CustomUser
    {
        public string Name { get; set; }
        public string Username { get; set; }
        public Guid Id { get; set; }
        public string[] Roles { get; set; }
    }
}
