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