using System;
using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;


namespace AsbCloudInfrastructure.Repository;

public class FileStorageRepository : IFileStorageRepository
{
    /// <summary>
    /// Директория хранения файлов
    /// </summary>

    public string RootPath { get; }
    

    public FileStorageRepository(IConfiguration configuration)
    {
        RootPath = configuration.GetValue<string>("ContentPath") ?? "../data";
    }

    public async Task SaveFileAsync(string filePathRec, Stream fileStreamSrc, CancellationToken token)
    {
        CreateDirectory(filePathRec);
        using var newfileStream = new FileStream(filePathRec, FileMode.Create);
        await fileStreamSrc.CopyToAsync(newfileStream, token).ConfigureAwait(false);
    }

    public void DeleteFiles(IEnumerable<string> filesName)
    {
        foreach (var fileName in filesName)
        {
            DeleteFile(fileName);
        }
    }
    
    public void DeleteDirectory(string path, bool isRecursive)
    {
        if (!Directory.Exists(path)) 
            return;

        if (!isRecursive)
        {
            var files = Directory.GetFiles(path);
            var directories = Directory.GetDirectories(path);

            if (files.Length != 0 || directories.Length != 0)
                throw new InvalidOperationException("Директория не пуста и не может быть удалена");
        }

        Directory.Delete(path, isRecursive);
    }

    public void DeleteFile(string fileName)
    {
        if (File.Exists(fileName))
            File.Delete(fileName);
    }

    public long GetFileLength(string srcFilePath)
    {
        var sysFileInfo = new FileInfo(srcFilePath);
        return sysFileInfo.Length;
    }

    public void MoveFile(string srcFilePath, string filePath)
    {
        CreateDirectory(filePath);
        File.Move(srcFilePath, filePath);
    }

    public string MakeFilePath(int idWell, int idCategory, string fileFullName, int fileId) =>
        MakeFilePath($"{idWell}",
                $"{idCategory}", 
                $"{fileId}" + $"{Path.GetExtension(fileFullName)}");

    public string MakeFilePath(string path1, string path2, string path3) =>
        Path.Combine(RootPath,
            path1,
            path2,
            path3);

    public int DeleteFilesNotInList(int idWell, IEnumerable<int> idsFilesList)
    {
        var allFilesPath = GetFilesPath(idWell);
        var result = 0;

        foreach (var filePath in allFilesPath)
        {
            if (int.TryParse(Path.GetFileNameWithoutExtension(filePath), out int idFile)
                || !idsFilesList.Any(x => x == idFile))
            {
                File.Delete(filePath);
                result++;
            }
        }

        return result;
    }

    public IEnumerable<FileInfoDto> GetListFilesNotDisc(IEnumerable<FileInfoDto> files)
    {
        var resutl = new List<FileInfoDto>();
        var groupFiles = files.GroupBy(x => x.IdWell);

        foreach (var itemGroupFiles in groupFiles)
        {
            var idsFilesStorage = GetIdsFiles(itemGroupFiles.Key);
            foreach (var file in files)
            {
                if (!idsFilesStorage.Any(x => x == file.Id))
                    resutl.Add(file);
            }
        }

        return resutl;
    }

    public string GetFilePath(int idWell, int idCategory, int idFile, string dotExtenstion) =>
        GetFilePath(idWell.ToString(), idCategory.ToString(), idFile, dotExtenstion);

    public string GetFilePath(string path1, string path2, int idFile, string dotExtenstion) =>
        Path.Combine(RootPath, path1, path2, $"{idFile}{dotExtenstion}");

    private IEnumerable<int> GetIdsFiles(int idWell)
    {
        var result = new List<int>();
        var allFilesPath = GetFilesPath(idWell);

        foreach (var filePath in allFilesPath)
            if (int.TryParse(Path.GetFileNameWithoutExtension(filePath), out int idFile))
                result.Add(idFile);

        return result;
    }

    private IEnumerable<string> GetFilesPath(int idWell)
    {
        var path = Path.Combine(RootPath, $"{idWell}");
        return Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
    }

    private static void CreateDirectory(string filePath)
    {
        var directoryName = Path.GetDirectoryName(filePath)!;
        Directory.CreateDirectory(directoryName);
    }
}