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.Requests;
using AsbCloudApp.Services;
using NSubstitute;
using Xunit;

namespace AsbCloudWebApi.Tests.UnitTests.Services;

public class FileServiceTest
{
	private const int idMark = 132;
	private const int idWell = 190;
	private const int idCategory = 10_000;
	private const int idFile = 1742;
	private const int idAuthor = 1;
	private const string fileName = "test.txt";

	private static readonly MemoryStream fileStream = new(Array.Empty<byte>());

	private static UserDto author = new()
	{
		Id = 1,
		IdCompany = 1
	};

	private static FileInfoDto fileInfo = new()
	{
		Id = idFile,
		IdAuthor = idAuthor,
		Author = author,
		IdWell = idWell,
		IdCategory = idCategory,
		Name = fileName,
		Size = 0,
		UploadDate = DateTime.Now
	};

	private static FileMarkDto fileMark = new()
	{
		Id = idMark,
		IdFile = idFile,
		User = author,
		Comment = "qqq",
		IdMarkType = 1,
		DateCreated = DateTime.Now,
		IsDeleted = false
	};

	private readonly IFileRepository fileRepositoryMock = Substitute.For<IFileRepository>();
	private readonly IFileStorageRepository storageRepositoryMock = Substitute.For<IFileStorageRepository>();

	private readonly FileService fileService;

	public FileServiceTest()
	{
		fileRepositoryMock.GetByMarkId(Arg.Any<int>(), Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(fileInfo);

		fileRepositoryMock.GetInfoByIdsAsync(Arg.Any<IEnumerable<int>>(), Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(new[] { fileInfo });

		fileRepositoryMock.DeleteAsync(Arg.Any<IEnumerable<int>>(), Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(new[] { fileInfo });

		fileRepositoryMock.MarkFileMarkAsDeletedAsync(Arg.Any<IEnumerable<int>>(), Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(fileMark.Id);

		fileRepositoryMock.MarkAsDeletedAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(fileMark.Id);

		fileRepositoryMock.GetInfosAsync(Arg.Any<FileRequest>(), Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(new[] { fileInfo });

		fileRepositoryMock.CreateFileMarkAsync(Arg.Any<FileMarkDto>(), Arg.Any<int>(), Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(fileMark.Id);

		fileRepositoryMock.GetOrDefaultAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
			.ReturnsForAnyArgs(fileInfo);

		storageRepositoryMock.GetFilePath(Arg.Any<int>(), Arg.Any<int>(), Arg.Any<int>(), Arg.Any<string>())
			.ReturnsForAnyArgs(Path.Combine("files", idWell.ToString(), idCategory.ToString(), fileName));

		fileService = new FileService(fileRepositoryMock, storageRepositoryMock);
	}

	[Fact]
	public async Task GetByMarkId_ShouldReturn_FileInfo()
	{
		//act
		var data = await fileService.GetByMarkId(idMark, CancellationToken.None);

		//assert
		Assert.NotNull(data);
	}

	[Fact]
	public async Task GetOrDefaultAsync_ShouldReturn_FileInfo()
	{
		//act
		var data = await fileService.GetOrDefaultAsync(idFile, CancellationToken.None);

		//assert
		Assert.NotNull(data);
	}

	[Fact]
	public async Task GetInfoByIdsAsync_ShouldReturn_FileInfo()
	{
		//act
		var data = await fileService.GetInfoByIdsAsync(new[] { idFile }, CancellationToken.None);

		//assert
		Assert.NotNull(data);
	}

	[Fact]
	public async Task SaveAsync_ShouldReturn_FileInfo()
	{
		//act
		var data = await fileService.SaveAsync(idWell, idAuthor, idCategory, fileName, fileStream, CancellationToken.None);

		//assert
		Assert.NotNull(data);
	}

	[Fact]
	public async Task DeleteAsync_ShouldReturn_DeletedRecordCount()
	{
		//act
		var result = await fileService.DeleteAsync(new[] { idFile }, CancellationToken.None);

		//assert
		Assert.True(result > 0);
	}

	[Fact]
	public async Task MarkFileMarkAsDeletedAsync_ShouldReturn_SavedRecordCount()
	{
		//act
		var result = await fileService.MarkFileMarkAsDeletedAsync(new[] { idMark }, CancellationToken.None);

		//assert
		Assert.True(result > 0);
	}

	[Fact]
	public async Task MarkAsDeletedAsync_ShouldReturn_DeletedRecordCount()
	{
		//act
		var result = await fileService.MarkAsDeletedAsync(idFile, CancellationToken.None);

		//assert
		Assert.True(result > 0);
	}

	[Fact]
	public async Task CreateFileMarkAsync_ShouldReturn_SavedRecordCount()
	{
		//act
		var result = await fileService.CreateFileMarkAsync(fileMark, idAuthor, CancellationToken.None);

		//assert
		Assert.True(result > 0);
	}
}