using AyCode.Database.Tests;
using AyCode.Utils.Extensions;
using Newtonsoft.Json;
using TIAM.Core;
using TIAM.Core.Enums;
using TIAM.Database.DataLayers.Admins;
using TIAM.Database.DbContexts.Admins;
using TIAM.Database.DbSets.Emails;
using TIAM.Entities.Drivers;
using TIAM.Entities.Emails;
using TIAM.Entities.Products;
using TIAM.Entities.Users;
using TIAM.Models.Dtos.Users;
using TIAM.Entities.Transfers;

namespace TIAM.Database.Test
{
    [TestClass]
    public class AdminDalTest : AcDatabaseTestModelBase<AdminDal, AdminDbContext>
    {
        [TestInitialize]
        public void Setup()
        {
        }

        [TestCleanup]
        public void TearDown()
        { }

        [DataTestMethod]
        [DataRow("42968456-6EF3-4D9C-8BC4-0569A129AC05")]
        public void GetPermissionViewBySubjectId_ReturnsPermissionContextMapping_WhenPermissionContextMappingExists(string subjectIdString)
        {
            var subjectId= Guid.Parse(subjectIdString);
            var permMapping = Dal.GetPermissionContextsViewBySubjectId(subjectId).ToList();
            
            Assert.IsNotNull(permMapping, "PermissionContextsView is null");
            Assert.IsTrue(permMapping.Count != 0, "PermissionContextsView count: 0");
        }

        [DataTestMethod]
        [DataRow("814b5495-c2e9-4f1d-a73f-37cd5d353078")]
        public void GetPermissionViewByContextId_ReturnsPermissionContextMapping_WhenPermissionContextMappingExists(string contextIdString)
        {
            var contextId = Guid.Parse(contextIdString);
            var permMapping = Dal.GetPermissionContextsViewByContextId(contextId).ToList();
            
            Assert.IsNotNull(permMapping, "PermissionContextsView is null");
            Assert.IsTrue(permMapping.Count != 0, "PermissionContextsView count: 0");
        }

        [DataTestMethod]
        [DataRow("814b5495-c2e9-4f1d-a73f-37cd5d353078")]
        public async Task GetPermissionContextMappingByContextIdAsync_ReturnsPermissionContextMapping_WhenPermissionContextMappingExists(string contextIdString)
        {
            var contextId = Guid.Parse(contextIdString);
            var permMapping = await Dal.GetPermissionContextsViewByContextIdAsync(contextId);
            
            Assert.IsNotNull(permMapping, "PermissionContextsView is null");
            Assert.IsTrue(permMapping.Count != 0, "PermissionContextsView count: 0");
        }

        public Product GetProductById_ReturnsProduct_WhenProductExists(string productIdString)
        {
            var productId = Guid.Parse(productIdString);
            var product = Dal.GetProductById(productId, true);
            
            Assert.IsNotNull(product, "Product is null");
            Assert.IsNotNull(product.Profile, "Profile is null");
            Assert.IsNotNull(product.Profile.Address, "Profile.Address is null");

            return product;
        }

        [DataTestMethod]
        public void GetProducts_ReturnProductsJson_WhenProductsExist()
        {
            var products = JsonConvert.DeserializeObject<List<Product>>(Dal.GetProductsJson(false));           

            Assert.IsNotNull(products, "Products is null");
            Assert.IsTrue(products.Count > 0, "No products found");

            Assert.IsNotNull(products[0].Profile, "Profile is null");
            Assert.IsNotNull(products[0].Profile.Address, "Profile.Address is null");

            Assert.IsNotNull(products[0].ServiceProvider, "ServiceProvider is null");

        }

        [DataTestMethod]
        [DataRow("3587F169-683C-4EEE-BCB5-E8D57F8C6DCE")]
        public void GetProductsByServiceProviderId_ReturnProductsJson_WhenProductsExist(string serviceProviderId)
        {
            var products = JsonConvert.DeserializeObject<List<Product>>(Dal.GetProductsJsonByServiceProviderId(Guid.Parse(serviceProviderId), true));

            Assert.IsNotNull(products, "Products is null");
            Assert.IsTrue(products.Count > 0, "No products found");

            Assert.IsNotNull(products[0].Profile, "Profile is null");
            Assert.IsNotNull(products[0].Profile.Address, "Profile.Address is null");

            Assert.IsNotNull(products[0].ServiceProvider, "ServiceProvider is null");
        }

        [DataTestMethod]
        [DataRow("814b5495-c2e9-4f1d-a73f-37cd5d353078")]
        public void GeProductById_ReturnsProduct_WhenHasUserProductMappingRelation(string productIdString)
        {
            var product = GetProductById_ReturnsProduct_WhenProductExists(productIdString);

            Assert.IsTrue(product.UserProductMappings.Count != 0, "UserProductMappings count: 0");

            Assert.IsNotNull(product.UserProductMappings[0].User, "User is null");
            Assert.IsNotNull(product.ServiceProvider, "ServiceProvider is null");
        }

        [DataTestMethod]
        [DataRow("540271F6-C604-4C16-8160-D5A7CAFEDF00")]
        public void GetUserById_ReturnsUser_WhenHasUserProductMappingRelation(string userIdString)
        {
            var userId = Guid.Parse(userIdString);
            var user = Dal.GetUserById(userId);

            Assert.IsNotNull(user);

            Assert.IsTrue(user.Id == userId, "user.Id != userId");
            Assert.IsTrue(user.UserProductMappings.Count != 0, "UserProductMappings count: 0");

            Assert.IsNotNull(user.UserProductMappings[0].Product, "Product is null");
        }

        #region UserProductMapping
        [DataTestMethod]
        //[DataRow("a24bf07a-76a7-48a4-813f-4a77e515b2f3")]
        [DataRow("71392cfd-fb9c-45c1-9540-7be3782cf26a")]
        public void GetUserProductMappingById_ReturnsUserProductMapping_WhenHasUserAndProductRelation(string userProductMappingIdString)
        {
            var userProductMappingId = Guid.Parse(userProductMappingIdString);
            var userProductMapping = Dal.GetUserProductMappingById(userProductMappingId, true);

            Assert.IsNotNull(userProductMapping);
            Assert.IsNotNull(userProductMapping.User, "User is null");
            Assert.IsNotNull(userProductMapping.Product, "Product is null");

            Assert.IsNotNull(userProductMapping.User.Profile.Address, "User.Profile.Address is null");
            Assert.IsNotNull(userProductMapping.Product.Profile.Address, "Product.Profile.Address is null");

            Assert.IsTrue(userProductMapping.Transfers?.Count != 0, "Transfers?.Count == 0");
            Assert.IsTrue(userProductMapping.Id == userProductMappingId, "userProductMapping.Id != userProductMappingId");
        }

        [DataTestMethod]
        [DataRow("97179a87-d99f-4f12-b7b2-75e21aaec6ab")]
        public void GetSerializedUserProductMappingCarByUserProductCarId_ReturnsUserProductMapping_WhenHasJsonDetailModelAndCar(string userProductCarIdString)
        {
            var userProductCarId = Guid.Parse(userProductCarIdString);

            var serializedUserProductMapping = Dal.Session(ctx 
                => ctx.UserProductMappings.FirstOrDefault(x 
                    => x.JsonDetailModel != null && x.JsonDetailModel.Cars != null && x.JsonDetailModel.Cars.Any(c => c.UserProductCarId == userProductCarId))?.ToJson());

            //var transfers = Dal.Session(x => x.GetTransfers()).ToList();

            //var userProductMappinIds = transfers.Select(x => x.UserProductMappingId).ToHashSet();
            //var userProductMappings = Dal.Session(x => x.UserProductMappings.Where(x => userProductMappinIds.Contains(x.Id)));

            Assert.IsNotNull(serializedUserProductMapping);
            Assert.IsFalse(serializedUserProductMapping.IsNullOrWhiteSpace());

            var userProductMapping = JsonConvert.DeserializeObject<UserProductMapping>(serializedUserProductMapping);
            //var car = userProductMapping.JsonDetailModel.Cars.FirstOrDefault(x => x.UserProductCarId == userProductCarId)?.Car;

            Assert.IsNotNull(userProductMapping);
            Assert.IsNotNull(userProductMapping.JsonDetailModel, "User is null");
            Assert.IsNotNull(userProductMapping.JsonDetailModel.Cars, "Product is null");

            Assert.IsTrue(userProductMapping.Transfers?.Count != 0);
            Assert.IsTrue(userProductMapping.JsonDetailModel.Cars.Count == 1);
            Assert.IsTrue(userProductMapping.JsonDetailModel.Cars[0].UserProductCarId == userProductCarId, "userProductMapping.JsonDetailModel.Cars[0].UserProductCarId == userProductCarId");
        }

        [DataTestMethod]
        [DataRow(["8EF2FC69-2338-4D9F-91B4-B1E15C241E1C", "814b5495-c2e9-4f1d-a73f-37cd5d353078"])]
        public async Task UserProductMappingCrudTest(string[] userIdProductIdStrings)
        {
            var userId = Guid.Parse(userIdProductIdStrings[0]);
            var productId = Guid.Parse(userIdProductIdStrings[1]);
            var userProductMappingId = Guid.NewGuid();

            await Dal.RemoveUserProductMappingAsync(userId, productId); //kitöröljük a szemetet, ha korábbról bentmaradt - J.

            var cars = new UserProductJsonDetailModel([new UserProductToCar(new Car())]);

            var userProductMapping = await Dal.AddUserProductMappingAsync(userProductMappingId, userId, productId, 2, cars);
            Assert.IsNotNull(userProductMapping);

            userProductMapping = await Dal.GetUserProductMappingByIdAsync(userProductMappingId, true);

            Assert.IsNotNull(userProductMapping);

            //userProductMapping.Permissions = 1;
            Assert.IsNotNull(await Dal.UpdateUserProductMappingAsync(userProductMappingId, 1));

            userProductMapping = await Dal.GetUserProductMappingByIdAsync(userProductMappingId, true);

            Assert.IsNotNull(userProductMapping);
            Assert.IsTrue(userProductMapping.Permissions == 1);

            Assert.IsNotNull(userProductMapping.User, "User is null");
            Assert.IsNotNull(userProductMapping.Product, "Product is null");

            Assert.IsTrue(userProductMapping.Id == userProductMappingId, "userProductMapping.Id != userProductMappingId");

            Assert.IsTrue(await Dal.RemoveUserProductMappingAsync(userProductMappingId)); //mielőbb kitöröljük, h ne maradjon szemét a db-ben - J.

            userProductMapping = await Dal.GetUserProductMappingByIdAsync(userProductMappingId, false);
            Assert.IsNull(userProductMapping); //a korábbi törlés miatt NULL kell legyen - J.
        }

        #endregion UserProductMapping

        [DataTestMethod]
        [DataRow("540271F6-C604-4C16-8160-D5A7CAFEDF00")]
        [DataRow("dcf451d2-cc4c-4ac2-8c1f-da00041be1fd")]
        [DataRow("ac612aa8-863b-4b4f-9d63-f5d261b5c5f9")]
        public void SerializeUserModelDto_ReturnDeserializedUser_WhenUserAndRelationsExists(string userIdString)
        {
            var userId = Guid.Parse(userIdString);

            JsonSerializerSettings options = new()
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                NullValueHandling = NullValueHandling.Ignore
            };

            var userModel = Dal.GetUserModelDtoById(userId);

            var serializedUserModel = JsonConvert.SerializeObject(userModel, options);
            userModel = JsonConvert.DeserializeObject<UserModelDto>(serializedUserModel);

            Assert.IsNotNull(userModel);
            Assert.IsNotNull(userModel.UserDto);
            Assert.IsNotNull(userModel.Profile);

            Assert.IsTrue(userModel.Id == userId, "userModel.Id != userId");

            if (userId != Guid.Parse("540271F6-C604-4C16-8160-D5A7CAFEDF00")) return; //csak az "540271F6.."-nek van product-ja! - J.

            Assert.IsTrue(userModel.Products.Count != 0);
            Assert.IsTrue(userModel.UserProductMappings.Count != 0);

            Assert.IsTrue(userModel.ServiceProviders.Count != 0);
            Assert.IsTrue(userModel.UserToServiceProviders.Count != 0);
        }

        [DataTestMethod]
        [DataRow("540271F6-C604-4C16-8160-D5A7CAFEDF00")]
        [DataRow("dcf451d2-cc4c-4ac2-8c1f-da00041be1fd")]
        [DataRow("ac612aa8-863b-4b4f-9d63-f5d261b5c5f9")]
        public void GetSerializedUserEntity_ReturnDeserializedUser_WhenUserAndRelationsExists(string userIdString)
        {
            var userId = Guid.Parse(userIdString);
            var userJson = Dal.GetUserJsonById(userId);

            Assert.IsFalse(userJson?.IsNullOrWhiteSpace());

            var user = JsonConvert.DeserializeObject<User>(userJson);

            Assert.IsNotNull(user);
            Assert.IsNotNull(user.Profile);
            Assert.IsNotNull(user.Profile.Address, "Profile.Address is null");

            Assert.IsTrue(user.Id == userId, "user.Id != userId");

            if (userId != Guid.Parse("540271F6-C604-4C16-8160-D5A7CAFEDF00")) return; //csak az "540271F6.."-nek van product-ja! - J.

            Assert.IsTrue(user.Products.Count != 0);
            Assert.IsTrue(user.UserProductMappings.Count != 0);

            Assert.IsTrue(user.ServiceProviders.Count != 0);
            Assert.IsTrue(user.UserToServiceProviders.Count != 0);
        }

        [TestMethod]
        public void GetSerializedUsers_ReturnDeserializedUsers_WhenUsersAndRelationsExists()
        {
            var userJson = Dal.GetUsersJson();

            Assert.IsFalse(userJson.IsNullOrWhiteSpace());

            var users = JsonConvert.DeserializeObject<List<User>>(userJson);

            Assert.IsNotNull(users);
            Assert.IsTrue(users.Count>0);
        }

        #region Transfer
        [DataTestMethod]
        [DataRow("6216f9fb-1dda-44bd-9d85-431f3cb09fde")]
        public void GetTransferById_ReturnsTransfer_WhenHasTransfer(string transferIdString)
        {
            var transferId = Guid.Parse(transferIdString);
            var transfer = Dal.GetTransferById(transferId);

            Assert.IsNotNull(transfer);
            Assert.IsNotNull(transfer.UserProductMapping);

            Assert.IsTrue(transfer.Id == transferId, "transfer.Id != transferId");
        }

        [DataTestMethod]
        [DataRow("273EFE3C-D19F-4C2A-BF19-7397DC835C60")]
        public void GetTransferDestionationById_ReturnsTransferDestination_WhenHasAddressRelation(string transferDestinationIdString)
        {
            var transferDestinationId = Guid.Parse(transferDestinationIdString);
            var transferDestination = Dal.GetTransferDestinationById(transferDestinationId);

            Assert.IsNotNull(transferDestination);
            Assert.IsNotNull(transferDestination.Address);

            Assert.IsTrue(transferDestination.Id == transferDestinationId, "transferDestination.Id != transferDestinationId");

            //Assert.IsTrue(user.UserProductMappings.Count != 0, "UserProductMappings count: 0");
            //Assert.IsNotNull(user.UserProductMappings[0].Product, "Product is null");
        }

        [DataTestMethod]
        [DataRow(["8f38f8e3-a92c-4979-88b1-dc812a82245f", "814b5495-c2e9-4f1d-a73f-37cd5d353078", "71392CFD-FB9C-45C1-9540-7BE3782CF26A"])]
        public async Task TransferCrudTest(string[] transferIdProductIdUserProductIdStrings)
        {
            var transferId = Guid.Parse(transferIdProductIdUserProductIdStrings[0]);
            var productId = Guid.Parse(transferIdProductIdUserProductIdStrings[1]);
            var userProductMappingId = Guid.Parse(transferIdProductIdUserProductIdStrings[2]);

            var fromAddress = "Budapest, Liszt Ferenc tér";
            var toAddress = "1211 Budapest, Kossuth Lajos utca 145";
            var userProductToCarId = Guid.Parse("97179a87-d99f-4f12-b7b2-75e21aaec6ab");

            await Dal.RemoveTransferAsync(transferId); //kitöröljük a szemetet, ha korábbról bentmaradt - J.

            var transfer = new Transfer
            {
                Id = transferId,
                ProductId = productId,
                //ReferralProductId = productId,
                Appointment = DateTime.UtcNow.AddDays(3),
                FlightNumber = "GSD234",
                FromAddress = fromAddress,
                ToAddress = toAddress,
                PassengerCount = 3,
                Price = 20000,
                TransferStatusType = TransferStatusType.OrderConfirmed,
            };

            Assert.IsTrue(await Dal.AddTransferAsync(transfer));
            Assert.IsNotNull(transfer);

            transfer = Dal.GetTransferById(transferId);

            Assert.IsNotNull(transfer);
            Assert.IsNull(transfer.UserProductMapping);

            transfer.Payed = true;
            transfer.UserProductToCarId = userProductToCarId;
            transfer.UserProductMappingId = userProductMappingId;
            transfer.TransferStatusType = TransferStatusType.AssignedToDriver;
            

            Assert.IsTrue(await Dal.UpdateTransferAsync(transfer));

            transfer = Dal.GetTransferById(transferId);

            Assert.IsNotNull(transfer);
            Assert.IsNotNull(transfer.UserProductMapping);

            Assert.IsTrue(transfer.Payed);
            Assert.IsTrue(transfer.UserProductToCarId == userProductToCarId);
            Assert.IsTrue(transfer.TransferStatusType == TransferStatusType.AssignedToDriver);
            Assert.IsTrue(transfer.Id == transferId, "transfer.Id != transferId");

            Assert.IsTrue(await Dal.RemoveTransferAsync(transferId)); //mielőbb kitöröljük, h ne maradjon szemét a db-ben - J.

            transfer = Dal.GetTransferById(transferId);
            Assert.IsNull(transfer); //a korábbi törlés miatt NULL kell legyen - J.
        }

        #endregion Transfer

        #region EmailMessage
        [DataTestMethod]
        [DataRow("f6ec3eed-5e00-47db-a6cf-804699515aa2")]
        public async Task GetEmailMessageById_ReturnsEmailMessage_WhenHasEmailMessage(string emailMessageIdString)
        {
            var emailMessageId = Guid.Parse(emailMessageIdString);
            var emailMessage = await Dal.GetEmailMessageByIdAsync(emailMessageId);

            Assert.IsNotNull(emailMessage);

            Assert.IsTrue(emailMessage.Recipients?.Count > 0);
            Assert.IsTrue(emailMessage.Id == emailMessageId, "emailMessage.Id != emailMessageId");
        }

        [DataTestMethod]
        [DataRow(["4CBAED43-2465-4D99-84F1-C8BC6B7025F7", "71392cfd-fb9c-45c1-9540-7be3782cf26a"])]
        public async Task GetMyEmailMessagesByUserProductMappingId_ReturnsEmailMessages_WhenHasEmailMessageAndAllRecipientIsValid(string[] userIdUserProductMappingIdString)
        {
            var userId = Guid.Parse(userIdUserProductMappingIdString[0]);
            var userProductMappingId = Guid.Parse(userIdUserProductMappingIdString[1]);

            var emailMessages = await Dal.GetEmailMessagesAsync(userId, userProductMappingId);

            Assert.IsNotNull(emailMessages);
            
            Assert.IsTrue(emailMessages.Count > 0);
            Assert.IsTrue(emailMessages.All(x => x.Recipients.Any(recipient => recipient.RecipientId == userId || recipient.RecipientId == userProductMappingId)));
        }

        [DataTestMethod]
        [DataRow(["718b04ef-47a7-444e-8527-54460a7f1ea3", "71392cfd-fb9c-45c1-9540-7be3782cf26a", "6216f9fb-1dda-44bd-9d85-431f3cb09fde", "test@tiam.hu", "AC612AA8-863B-4B4F-9D63-F5D261B5C5F9"])]
        public async Task EmailMessageCrudTest(string[] emailIdSenderIdContextIdSenderEmailRecipientIdStrings)
        {
            var emailMessageId = Guid.Parse(emailIdSenderIdContextIdSenderEmailRecipientIdStrings[0]);
            var senderId = Guid.Parse(emailIdSenderIdContextIdSenderEmailRecipientIdStrings[1]);
            var contextId = Guid.Parse(emailIdSenderIdContextIdSenderEmailRecipientIdStrings[2]);
            var senderEmail = emailIdSenderIdContextIdSenderEmailRecipientIdStrings[3];
            var recipientId = Guid.Parse(emailIdSenderIdContextIdSenderEmailRecipientIdStrings[4]);

            var subject = "Transfer - Budapest, Liszt Ferenc tér";
            var text = "1211 Budapest, Kossuth Lajos utca 145";
            
            await Dal.RemoveEmailMessageAsync(emailMessageId); //kitöröljük a szemetet, ha korábbról bentmaradt - J.

            var emailMessage = new EmailMessage(emailMessageId, senderId, contextId, subject, text, senderEmail);
            emailMessage.Recipients.Add(new EmailRecipient(id: Guid.NewGuid(), recipientId, emailMessageId));


            Assert.IsTrue(await Dal.AddEmailMessageAsync(emailMessage));
            Assert.IsNotNull(emailMessage);

            emailMessage = await Dal.GetEmailMessageByIdAsync(emailMessageId);

            Assert.IsNotNull(emailMessage);
            Assert.IsTrue(emailMessage.Recipients?.Count > 0);

            var modifiedText = "modifiedText";
            emailMessage.Text = modifiedText;
            

            Assert.IsTrue(await Dal.UpdateEmailMessageAsync(emailMessage));

            emailMessage = await Dal.GetEmailMessageByIdAsync(emailMessageId);

            Assert.IsNotNull(emailMessage);
            Assert.IsTrue(emailMessage.Recipients?.Count > 0);

            Assert.IsTrue(emailMessage.Text == modifiedText);
            Assert.IsTrue(emailMessage.Id == emailMessageId, "emailMessage.Id != emailMessageId");

            Assert.IsTrue(await Dal.RemoveEmailMessageAsync(emailMessageId)); //mielőbb kitöröljük, h ne maradjon szemét a db-ben - J.

            emailMessage = await Dal.GetEmailMessageByIdAsync(emailMessageId);
            Assert.IsNull(emailMessage); //a korábbi törlés miatt NULL kell legyen - J.
        }

        #endregion EmailMessage
    }
}
 