using EnotaryoPH.Data;
using EnotaryoPH.Data.Entities;
using Exadel.Compreface.Clients.CompreFaceClient;
using Exadel.Compreface.DTOs.FaceVerificationDTOs.FaceVerification;
using Exadel.Compreface.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace EnotaryoPH.Web.Pages
{
    public class BaseTakeSelfiePageModel : PageModel
    {
        protected readonly NotaryoDBContext _notaryoDBContext;
        private readonly ICompreFaceClient _compreFaceClient;
        private readonly IConfiguration _configuration;
        private readonly ICurrentUserService _currentUserService;
        private Transaction _transactionEntity;
        private User _user;

        public BaseTakeSelfiePageModel(NotaryoDBContext notaryoDBContext, ICurrentUserService currentUserService, ICompreFaceClient compreFaceClient, IConfiguration configuration)
        {
            _notaryoDBContext = notaryoDBContext;
            _currentUserService = currentUserService;
            _compreFaceClient = compreFaceClient;
            _configuration = configuration;
        }

        protected async Task<bool> PostAsync()
        {
            var selfieImage = Convert.FromBase64String(SelfieBase64Image.Split(",")[1]) ?? [];
            var identificationDocument = _notaryoDBContext.IdentificationDocuments.First(e => e.UserID == CurrentUser.UserID);
            var faceMatches = await VerifySelfieAsync(selfieImage, identificationDocument);

            var isMatchSuccess = faceMatches.Any();
            if (isMatchSuccess)
            {
                var signatory = _notaryoDBContext.TransactionSignatories.Include(ts => ts.Transaction).FirstOrDefault(x => x.UserID == CurrentUser.UserID);
                if (signatory != null)
                {
                    signatory.Status = nameof(SignatoryStatus.FaceMatch);
                    _notaryoDBContext.Update(signatory);
                    _transactionEntity = signatory.Transaction;
                    Transaction_UID = _transactionEntity.Transaction_UID.Value;
                }
                else if (!CurrentUser.Role.IsInList(nameof(UserType.Principal), nameof(UserType.SuperUser), nameof(UserType.Administrator)))
                {
                    return false;
                }

                if (CurrentTransaction.TransactionID == 0)
                {
                    var newTransaction = new Transaction
                    {
                        Transaction_UID = Guid.CreateVersion7(DateTime.UtcNow),
                        CreatedOn = DateTime.UtcNow,
                        TransactionDate = DateTime.UtcNow,
                        Status = nameof(TransactionState.New),
                        PrincipalID = CurrentUser.UserID
                    };
                    _notaryoDBContext.Add(CurrentTransaction);
                }

                var selfieEntity = CreateOrUpdateSelfie(selfieImage);
                selfieEntity.Transaction = CurrentTransaction;
                selfieEntity.IdentificationDocumentID = identificationDocument.IdentificationDocumentID;
                _notaryoDBContext.UpdateOrCreate(selfieEntity);
                _notaryoDBContext.SaveChanges();
            }
            return isMatchSuccess;
        }

        private TransactionSelfie CreateOrUpdateSelfie(byte[] selfieImage)
        {
            TransactionSelfie selfieEntity;
            if (TransactionSelfie_UID == Guid.Empty)
            {
                selfieEntity = new TransactionSelfie
                {
                    CreatedOn = DateTime.UtcNow,
                    TransactionSelfie_UID = Guid.CreateVersion7(DateTime.UtcNow),
                    UserID = CurrentUser.UserID,
                    TransactionID = CurrentTransaction.TransactionID,
                };
                TransactionSelfie_UID = selfieEntity.TransactionSelfie_UID.Value;
            }
            else
            {
                selfieEntity = _notaryoDBContext.TransactionSelfies.FirstOrDefault(e => e.TransactionSelfie_UID == TransactionSelfie_UID);
            }
            selfieEntity.File = Convert.FromBase64String(SelfieBase64Image.Split(",")[1]);
            return selfieEntity;
        }

        private async Task<IEnumerable<FaceMatches>> VerifySelfieAsync(byte[] selfieImage, IdentificationDocument identificationDocument)
        {
            var selfiePath = Path.Combine(Path.GetTempPath(), "Selfies");
            if (!Directory.Exists(selfiePath))
            {
                Directory.CreateDirectory(selfiePath);
            }
            var identificationDocumentPath = Path.Combine(selfiePath, $"{identificationDocument.IdentificationDocument_UID}.jpg");

            var apiKey = _configuration.GetValue<string>("CompreFaceConfig:APIKey");
            var client = _compreFaceClient.GetCompreFaceService<VerificationService>(apiKey);
            var faceVerificationRequest = new FaceVerificationRequestByBytes()
            {
                SourceImageInBytes = selfieImage,
                TargetImageInBytes = identificationDocument.File,
                DetProbThreshold = 0.81m,
                Limit = 1,
                Status = false,
                FacePlugins = []
            };
            var result = await client.VerifyAsync(faceVerificationRequest);
            var faceMatches = result.Result.SelectMany(x => x.FaceMatches);
            return faceMatches;
        }

        [BindProperty]
        public string SelfieBase64Image { get; set; }

        [BindProperty(SupportsGet = true)]
        public Guid Transaction_UID { get; set; }

        [BindProperty(SupportsGet = true)]
        public Guid TransactionSelfie_UID { get; set; }

        protected User CurrentUser => _user ??= _notaryoDBContext.Users.AsNoTracking().First(x => x.User_UID == _currentUserService.GetUser_UID());

        protected Transaction CurrentTransaction => _transactionEntity
            ??= _notaryoDBContext.Transactions.AsNoTracking().FirstOrDefault(x => x.Transaction_UID == Transaction_UID)
            ?? new Transaction
            {
                Transaction_UID = Guid.CreateVersion7(DateTime.UtcNow),
                CreatedOn = DateTime.UtcNow,
                TransactionDate = DateTime.UtcNow,
                Status = nameof(TransactionState.New),
                PrincipalID = CurrentUser.UserID
            };
    }
}