using System.Net;
using AsbCloudApp.Data;
using AsbCloudWebApi.IntegrationTests.Clients;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Xunit;

namespace AsbCloudWebApi.IntegrationTests.Controllers;

public class AdminDepositControllerTest : BaseIntegrationTest
{
	private static readonly DepositBaseDto dto = new()
	{
		Caption = "test",
		Latitude = 90,
		Longitude = 100,
		Timezone = new SimpleTimezoneDto
		{
			Hours = 1
		}
	};

	private readonly IAdminDepositClient client;

	public AdminDepositControllerTest(WebAppFactoryFixture factory)
		: base(factory)
	{
		client = factory.GetAuthorizedHttpClient<IAdminDepositClient>(string.Empty);
	}

	[Fact]
	public async Task Insert_returns_success()
	{
		//act
		var response = await client.InsertAsync(dto);

		//assert
		Assert.Equal(HttpStatusCode.OK, response.StatusCode);
		Assert.True(response.Content > 0);

		var entity = await dbContext.Deposits.FirstOrDefaultAsync(d => d.Id == response.Content);
		var deposit = entity?.Adapt<DepositBaseDto>();

		var excludeProps = new[] { nameof(DepositBaseDto.Id) };
		MatchHelper.Match(dto, deposit, excludeProps);
	}

	[Fact]
	public async Task InsertRange_returns_success()
	{
		//act
		var responce = await client.InsertRangeAsync(new[] { dto });

		//assert
		Assert.Equal(HttpStatusCode.OK, responce.StatusCode);
		Assert.Equal(1, responce.Content);

		var entity = await dbContext.Deposits.OrderBy(d => d.Id).LastOrDefaultAsync();
		var deposit = entity?.Adapt<DepositBaseDto>();

		var excludeProps = new[] { nameof(DepositBaseDto.Id) };
		MatchHelper.Match(dto, deposit, excludeProps);
	}

	[Fact]
	public async Task Update_returns_BadRequest_for_IdDeposit()
	{
		//arrange
		var dtoBad = dto.Adapt<DepositBaseDto>();

		//act
		var response = await client.UpdateAsync(dtoBad);

		//assert
		Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
	}

	[Fact]
	public async Task Update_returns_success()
	{
		//arrange
		var insertResponse = await client.InsertAsync(dto);

		dto.Id = insertResponse.Content;
		dto.Caption = "Test";
		dto.Latitude = 50;
		dto.Longitude = 50;
		dto.Timezone = new SimpleTimezoneDto
		{
			IsOverride = true,
			Hours = 12
		};

		//act
		var response = await client.UpdateAsync(dto);

		//assert
		Assert.Equal(HttpStatusCode.OK, response.StatusCode);
		Assert.True(response.Content > 0);

		var entity = await dbContext.Deposits.FirstOrDefaultAsync(d => d.Id == response.Content);
		var deposit = entity?.Adapt<DepositBaseDto>();

		MatchHelper.Match(dto, deposit);
	}

	[Fact]
	public async Task GetOrDefault_returns_success()
	{
		//arrange
		var insertResponse = await client.InsertAsync(dto);
		var id = insertResponse.Content;

		//act
		var response = await client.GetOrDefaultAsync(id);

		//assert
		Assert.Equal(HttpStatusCode.OK, response.StatusCode);
		Assert.NotNull(response.Content);

		var deposit = response.Content;

		var excludeProps = new[] { nameof(DepositBaseDto.Id) };
		MatchHelper.Match(dto, deposit, excludeProps);
	}

	[Fact]
	public async Task GetOrDefault_returns_NoContent_for_IdDeposit()
	{
		//act
		var responce = await client.GetOrDefaultAsync(0);

		//assert
		Assert.Equal(HttpStatusCode.NoContent, responce.StatusCode);
	}

	[Fact]
	public async Task GetAll_returns_success()
	{
		//act
		var response = await client.GetAllAsync();

		//assert
		Assert.Equal(HttpStatusCode.OK, response.StatusCode);
		Assert.NotNull(response.Content);

		var expectedCount = await dbContext.Deposits.CountAsync();
		Assert.Equal(expectedCount, response.Content.Count());
	}

	[Fact]
	public async Task Delete_returns_success()
	{
		//arrange
		var insertResponse = await client.InsertAsync(dto);
		var id = insertResponse.Content;

		//act
		var response = await client.DeleteAsync(id);

		//assert
		Assert.Equal(HttpStatusCode.OK, response.StatusCode);
		Assert.True(response.Content > 0);

		var entity = await dbContext.Deposits.FirstOrDefaultAsync(d => d.Id == dto.Id);
		Assert.Null(entity);
	}

	[Fact]
	public async Task Delete_returns_NoContent_IdDeposit()
	{
		//act
		var response = await client.DeleteAsync(0);

		//assert
		Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
	}
}