using AyCode.Database.DataLayers;
using AyCode.Database.Tests;
using AyCode.Database.Tests.Users;
using Microsoft.EntityFrameworkCore;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
using System.Text.Json;
using TIAM.Database.DataLayers.Users;
using TIAM.Database.DbContexts.Users;
using TIAM.Entities.Profiles;
using TIAM.Entities.Users;
using TIAM.Models.Dtos.Users;
using AyCode.Interfaces.Users.Dtos;
using TIAM.Entities.ServiceProviders;
using TIAM.Entities.Addresses;

namespace TIAM.Database.Test
{
    [TestClass]
    public class UserDalTests : AcUserDalTestBase<UserDal, UserDbContext, User, Profile, UserToken, TiamServiceProvider, UserToServiceProvider, Address>
    {
        private Mock<UserDbContext> _mockContext;

        [TestInitialize]
        public void TestInitialize()
        {
            //var options = new DbContextOptionsBuilder<UserDbContext>()
            //    .UseInMemoryDatabase(databaseName: "UserDatabase")
            //    .Options;

            //_mockContext = new Mock<UserDbContext>(options);

            //var mockSet = new Mock<DbSet<User>>();
            //_mockContext.Setup(c => c.Users).Returns(mockSet.Object);

            //_userDal = new UserDal(_mockContext.Object);
        }

        [TestMethod]
        [DataRow("540271F6-C604-4C16-8160-D5A7CAFEDF00")]
        public void GetUserById_ReturnsUser_WhenUserAndRelationsExists(string userIdString)
        {
            var user = AcBase_GetUserById_ReturnsUser_WhenUserExists(userIdString);

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

        [TestMethod]
        [DataRow("test@tiam.hu")]
        public void GetUserByEmail_ReturnsUser_WhenUserAndRelationsExists(string email)
        {
            var user = AcBase_GetUserByEmail_ReturnsUser_WhenUserExists(email);

            Assert.IsTrue(user.ServiceProviders.Count > 0);
            Assert.IsTrue(user.UserToServiceProviders.Count > 0);
        }
        
        [TestMethod]
        [DataRow("test@tiam.hu")]
        public async Task GetUserByEmailAsync_ReturnsUser_WhenUserAndRelationsExists(string email)
        {
            var user = await AcBase_GetUserByEmailAsync_ReturnsUser_WhenUserExists(email);

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

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

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

            var userModel = await Dal.GetUserModelDtoByIdAsync(userId).ConfigureAwait(false);

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

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

            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);
        }

        //[TestMethod]
        //[DataRow("test@tiam.hu")]
        //public async Task GetUserByEmailAsync_ReturnsUser_WhenUserExists(string email)
        //{
        //    // Arrange
        //    var user = new User { EmailAddress = email };
        //    var users = new[] { user }.AsQueryable();

        //    var mockSet = new Mock<DbSet<User>>();
        //    mockSet.As<IQueryable<User>>().Setup(m => m.Provider).Returns(users.Provider);
        //    mockSet.As<IQueryable<User>>().Setup(m => m.Expression).Returns(users.Expression);
        //    mockSet.As<IQueryable<User>>().Setup(m => m.ElementType).Returns(users.ElementType);
        //    mockSet.As<IQueryable<User>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());

        //    _mockContext.Setup(c => c.Users).Returns(mockSet.Object);

        //    // Act
        //    var result = await _userDal.GetUserByEmailAsync(email);

        //    // Assert
        //    Assert.IsNotNull(result);
        //    Assert.AreEqual(email, result.EmailAddress);
        //}

        //[TestMethod]
        //[DataRow("TEST@TEST.COM")]
        //public async Task GetUserByEmailAsync_ReturnsNull_WhenUserDoesNotExist(string email)
        //{
        //    // Arrange
        //    var users = new User[0].AsQueryable();

        //    var mockSet = new Mock<DbSet<User>>();
        //    mockSet.As<IQueryable<User>>().Setup(m => m.Provider).Returns(users.Provider);
        //    mockSet.As<IQueryable<User>>().Setup(m => m.Expression).Returns(users.Expression);
        //    mockSet.As<IQueryable<User>>().Setup(m => m.ElementType).Returns(users.ElementType);
        //    mockSet.As<IQueryable<User>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());

        //    _mockContext.Setup(c => c.Users).Returns(mockSet.Object);

        //    // Act
        //    var result = await _userDal.GetUserByEmailAsync(email);

        //    // Assert
        //    Assert.IsNull(result);
        //}

        //[TestMethod]
        //[DataRow("TEST@TEST.COM", "+1234567890", "password")]
        //public async Task CreateUserAsync_ShouldReturnTrue_WhenUserIsCreated(string email, string phoneNumbr, string password)
        //{
        //    // Arrange
        //    var user = new User
        //    {
        //        Id = Guid.NewGuid(),
        //        EmailAddress = email,
        //        PhoneNumber = phoneNumbr,
        //        Password = password
        //    };

        //    var mockSet = new Mock<DbSet<User>>();
        //    _mockContext.Setup(x => x.Users).Returns(mockSet.Object);
        //    _mockContext.Setup(x => x.Users.Add(user)).Returns(() => null);

        //    _mockContext.Setup(x => x.SaveChangesAsync(It.IsAny<CancellationToken>()))
        //    .ReturnsAsync(1)
        //    .Verifiable();

        //    // Act
        //    var result = await _userDal.CreateUserAsync(user);

        //    // Assert
        //    Assert.IsTrue(result);
        //}

        //[TestMethod]
        //[DataRow("TEST@TEST.COM", "+1234567890", "password")]
        //public async Task UpdateUserAsync_ShouldUpdateUser(string email, string phoneNumbr, string password)
        //{
        //    // Arrange
        //    var user = new User(Guid.NewGuid(), email, phoneNumbr, password);
        //    _mockContext.Object.Users.Add(user);
        //    await _mockContext.Object.SaveChangesAsync();

        //    // Act
        //    user.EmailAddress = email;
        //    var result = await _userDal.UpdateUserAsync(user);

        //    // Assert
        //    Assert.IsTrue(result);
        //    var updatedUser = _mockContext.Object.Users.Single(u => u.EmailAddress == user.EmailAddress);
        //    Assert.AreEqual(email, updatedUser.EmailAddress);
        //}
    }
}