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 AsbCloudInfrastructure.Tests.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 = DateTimeOffset.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);
    }
}