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