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