using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.User;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudApp.Services.Notifications;
using AsbCloudInfrastructure.Services;
using Microsoft.Extensions.Configuration;
using NSubstitute;
using Xunit;

namespace AsbCloudWebApi.Tests.UnitTests.Services;

public class WellFinalDocumentsServiceTest
{
	private const int idWell = 1;
	private const int validInsertedFileId = 555;
	private const int idWellFinalDocCategory = 10_000;
	private const string editPublisherPermission = "WellFinalDocuments.editPublisher";
	private const string fileName = "test.txt";
	
	private static readonly MemoryStream fileStream = new(Array.Empty<byte>());

	private static readonly WellFinalDocumentDto wellFinalDocument = new()
	{
		IdCategory = idWellFinalDocCategory,
		PermissionToUpload = true,
		Publishers = new List<UserDto>
		{
			new()
			{
				Id = 1
			}
		}
	};

	private static readonly UserExtendedDto user = new()
	{
		Id = 1,
		IdCompany = 1,
		Surname = "Tester 1",
		Name = "Peppa",
		Email = "test@test.com"
	};

	private static readonly WellCaseDto wellCase = new()
	{
		IdWell = 1,
		PermissionToSetPubliher = true,
		WellFinalDocuments = new[] { wellFinalDocument }
	};

	private static readonly WellFinalDocumentDBDto wellFinalDocumentDB = new()
	{
		IdCategory = idWellFinalDocCategory,
		IdUser = 1,
		IdWell = 1
	};

	private static readonly NotificationCategoryDto notificationCategory = new()
	{
		Id = 20000,
		Name = "Системные уведомления"
	};

	private static readonly WellDto well = new()
	{
		Id = 1,
		Caption = "well 1",
		Cluster = "cluster 1",
		Deposit = "deposit 1"
	};

	private static readonly FileCategoryDto fileCategory = new()
	{
		Id = idWellFinalDocCategory,
		Name = "Проект на бурение транспортного и горизонтального участков скважины"
	};

	private readonly IConfiguration configuration = new ConfigurationBuilder().Build();
	private readonly IUserRepository userRepositoryMock = Substitute.For<IUserRepository>();
	private readonly IFileCategoryService fileCategoryServiceMock = Substitute.For<IFileCategoryService>();
	private readonly ICrudRepository<NotificationCategoryDto> notificationCategoryRepositoryMock = Substitute.For<ICrudRepository<NotificationCategoryDto>>();
	private readonly IFileRepository fileRepositoryMock = Substitute.For<IFileRepository>();
	private readonly IWellFinalDocumentsRepository wellFinalDocumentsRepositoryMock = Substitute.For<IWellFinalDocumentsRepository>();
	private readonly IWellService wellServiceMock = Substitute.For<IWellService>();
	private readonly INotificationRepository notificationRepositoryMock = Substitute.For<INotificationRepository>();
	private readonly INotificationTransportService notificationTransportServiceMock = Substitute.For<INotificationTransportService>();
	private readonly IFileStorageRepository fileStorageRepositoryMock = Substitute.For<IFileStorageRepository>();

	private readonly WellFinalDocumentsService wellFinalDocumentsService;
	private readonly FileService fileService;
	private readonly NotificationService notificationService;

	
	public WellFinalDocumentsServiceTest()
	{
		wellFinalDocumentsRepositoryMock.GetByWellIdAsync(Arg.Any<int>(), Arg.Any<int>(), Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(wellCase);

		wellFinalDocumentsRepositoryMock.GetCategoryAsync(Arg.Any<int>(), Arg.Any<int>(), Arg.Any<int>(), Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(wellFinalDocumentDB);

		fileRepositoryMock.InsertAsync(Arg.Any<FileInfoDto>(), Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(validInsertedFileId);

		fileRepositoryMock.GetOrDefaultAsync(validInsertedFileId, Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(new FileInfoDto { Id = validInsertedFileId });

		userRepositoryMock.GetAllAsync(Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(new[] { user });

		userRepositoryMock.GetOrDefault(Arg.Any<int>())
			.ReturnsForAnyArgs(user);

		userRepositoryMock.GetOrDefaultAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(user);

		userRepositoryMock.HasPermission(user.Id, editPublisherPermission)
			.ReturnsForAnyArgs(true);

		wellServiceMock.GetOrDefaultAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(well);

		notificationCategoryRepositoryMock.GetOrDefaultAsync(Arg.Any<int>(),
				Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(notificationCategory);

		fileCategoryServiceMock.GetOrDefaultAsync(idWellFinalDocCategory, Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(fileCategory);

		notificationService = new NotificationService(notificationCategoryRepositoryMock,
			notificationRepositoryMock,
			new[] { notificationTransportServiceMock });

		fileService = new FileService(fileRepositoryMock, fileStorageRepositoryMock);

		wellFinalDocumentsService = new WellFinalDocumentsService(fileService, userRepositoryMock, wellServiceMock, configuration,
			fileCategoryServiceMock,
			wellFinalDocumentsRepositoryMock,
			notificationService);
	}

	[Fact]
	public async Task GetHistoryFileByIdCategory_ShouldReturn_EmptyHistory()
	{
		//act
		var data = await wellFinalDocumentsService.GetFilesHistoryByIdCategoryAsync(idWell, idWellFinalDocCategory, CancellationToken.None);
		
		//assert
		Assert.NotNull(data);
		Assert.Empty(data.Files);
	}

	[Fact]
	public async Task SaveCategoryFile_ShouldReturn_FileId()
	{
		//act
		var idFile = await wellFinalDocumentsService.SaveCategoryFileAsync(idWell, idWellFinalDocCategory, user.Id, fileStream, fileName, CancellationToken.None);
		
		//assert
		Assert.Equal(validInsertedFileId, idFile);
	}
}