using AsbCloudDb.Model;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Refit;
using System.Net.Http.Headers;
using System.Text.Json;
using AsbCloudDb;
using AsbCloudWebApi.IntegrationTests.Converters;

namespace AsbCloudWebApi.IntegrationTests;

public class WebAppFactoryFixture : WebApplicationFactory<Startup>
{
   private static readonly JsonSerializerOptions JsonSerializerOptions = new()
   {
      PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
      PropertyNameCaseInsensitive = true,
      Converters = { new ValidationResultConverter() }
   };

   private static readonly RefitSettings RefitSettings = new(new SystemTextJsonContentSerializer(JsonSerializerOptions));

   private readonly string connectionString;

   public WebAppFactoryFixture()
   {
      var configuration = new ConfigurationBuilder()
         .AddJsonFile("appsettings.Tests.json")
         .Build();
      
      var dbConnection = configuration.GetSection("DbConnection").Get<DbConnection>()!;
      connectionString = dbConnection.GetConnectionString();
   }
   
   protected override void ConfigureWebHost(IWebHostBuilder builder)
   {
      builder.ConfigureServices(services =>
      {
         var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<AsbCloudDbContext>));

         if (descriptor != null)
            services.Remove(descriptor);

         services.AddDbContext<AsbCloudDbContext>(options =>
            options.UseNpgsql(connectionString));

         var serviceProvider = services.BuildServiceProvider();

         using var scope = serviceProvider.CreateScope();
         var scopedServices = scope.ServiceProvider;
         var dbContext = scopedServices.GetRequiredService<AsbCloudDbContext>();

         dbContext.Database.EnsureCreatedAndMigrated();
         dbContext.Deposits.AddRange(Data.Defaults.Deposits);
         dbContext.SaveChanges();
      });
   }

   public override async ValueTask DisposeAsync()
   {
      var dbContext = new AsbCloudDbContext(
         new DbContextOptionsBuilder<AsbCloudDbContext>()
            .UseNpgsql(connectionString)
            .Options);

      await dbContext.Database.EnsureDeletedAsync();
   }

   public T GetAuthorizedHttpClient<T>(string uriSuffix)
   {
      var httpClient = GetAuthorizedHttpClient();
      if (string.IsNullOrEmpty(uriSuffix))
         return RestService.For<T>(httpClient, RefitSettings);

      if (httpClient.BaseAddress is not null)
         httpClient.BaseAddress = new Uri(httpClient.BaseAddress, uriSuffix);

      return RestService.For<T>(httpClient, RefitSettings);
   }

   private HttpClient GetAuthorizedHttpClient()
   {
      var httpClient = CreateClient();
      var jwtToken = ApiTokenHelper.GetAdminUserToken();
      httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
      return httpClient;
   }
}