using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;

namespace AsbCloudInfrastructure.Services;

/// <summary>
/// Реализация сервиса для справок по страницам
/// </summary>
public class HelpPageService : IHelpPageService
{
    private readonly string directoryNameHelpPageFiles; 
    private readonly IHelpPageRepository helpPageRepository;
    private readonly IFileStorageRepository fileStorageRepository;

    /// <summary>
    /// Конструктор класса
    /// </summary>
    /// <param name="helpPageRepository"></param>
    /// <param name="fileStorageRepository"></param>
    /// <param name="configuration"></param>
    public HelpPageService(IHelpPageRepository helpPageRepository,
        IFileStorageRepository fileStorageRepository,
        IConfiguration configuration)
    {        
        this.helpPageRepository = helpPageRepository;
        this.fileStorageRepository = fileStorageRepository;
        directoryNameHelpPageFiles = configuration.GetValue<string>("DirectoryNameHelpPageFiles");

        if (string.IsNullOrWhiteSpace(directoryNameHelpPageFiles))
            directoryNameHelpPageFiles = "helpPages";
    }

    /// <summary>
    /// Метод обновления или обновления файла справки
    /// </summary>
    /// <param name="urlPage"></param>
    /// <param name="idCategory"></param>
    /// <param name="fileName"></param>
    /// <param name="fileStream"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task<int> AddOrUpdateAsync(string urlPage, 
        int idCategory, 
        string fileName, 
        Stream fileStream, 
        CancellationToken cancellationToken)
    {
        var helpPage = await helpPageRepository.GetOrDefaultByUrlPageAndIdCategoryAsync(urlPage,
            idCategory,
            cancellationToken);

        if(helpPage is not null)
        {
            await UpdateFileAsync(helpPage,
                idCategory,
                fileName,
                fileStream,
                cancellationToken);

            return helpPage.Id;
        }

        return await SaveFileAsync(urlPage,
            idCategory,
            fileName,
            fileStream,
            cancellationToken);
    }


    /// <summary>
    /// Метод получения файла справки
    /// </summary>
    /// <param name="pageKey"></param>
    /// <param name="idCategory"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task<(Stream stream, string fileName)?> GetFileStreamAsync(string pageKey,
        int idCategory,
        CancellationToken cancellationToken)
    {
        pageKey = WebUtility.UrlDecode(pageKey);
        
        var helpPage = await helpPageRepository.GetOrDefaultByUrlPageAndIdCategoryAsync(pageKey,
            idCategory,
            cancellationToken);
        
        if(helpPage is null)
            return null;

        string filePath = fileStorageRepository.GetFilePath(directoryNameHelpPageFiles,
            helpPage.IdCategory.ToString(),
            helpPage.Id,
            Path.GetExtension(helpPage.Name));

        var fileStream = new FileStream(Path.GetFullPath(filePath), FileMode.Open);

        return (fileStream, helpPage.Name);
    }

    private async Task<int> SaveFileAsync(string urlPage,
        int idCategory,
        string fileName,
        Stream fileStream,
        CancellationToken cancellationToken)
    {
        HelpPageDto helpPage = new()
        {
            UrlPage = urlPage,
            IdCategory = idCategory,
            Name = Path.GetFileName(fileName),
            Size = fileStream.Length,
        };

        int idFile = await helpPageRepository.InsertAsync(helpPage,
            cancellationToken);

        await SaveFileAsync(idCategory,
            fileName,
            fileStream,
            idFile,
            cancellationToken);

        return idFile;
    }

    private async Task UpdateFileAsync(HelpPageDto helpPage,
        int idCategory,
        string fileName,
        Stream fileStream,
        CancellationToken cancellationToken)
    {
        helpPage.Name = Path.GetFileName(fileName);
        helpPage.IdCategory = idCategory;
        helpPage.Size = fileStream.Length;

        string fileFullName = fileStorageRepository.GetFilePath(directoryNameHelpPageFiles,
            idCategory.ToString(),
            helpPage.Id,
            Path.GetExtension(helpPage.Name));

        await helpPageRepository.UpdateAsync(helpPage,
            cancellationToken);

        fileStorageRepository.DeleteFile(fileFullName);

        await SaveFileAsync(helpPage.IdCategory,
            fileName,
            fileStream,
            helpPage.Id,
            cancellationToken);
    }

    private async Task SaveFileAsync(int idCategory,
        string fileName,
        Stream fileStream,
        int fileId,
        CancellationToken cancellationToken)
    {
        string filePath = fileStorageRepository.MakeFilePath(directoryNameHelpPageFiles,
            idCategory.ToString(),
            $"{fileId}" + $"{Path.GetExtension(fileName)}");

        await fileStorageRepository.SaveFileAsync(filePath,
            fileStream,
            cancellationToken);
    }
}