using IWS5.Importer.Abstractions.Interfaces;
using Serilog.Context;

namespace IWS5.Importer.Worker.FileSystem;

public class FileCleaner : IFileCleaner
{
    private readonly int _copyLifeDays;
    private readonly Serilog.ILogger _logger;

    public FileCleaner(IGeneralImportSettingsProvider settingsProvider, Serilog.ILogger logger)
    {
        _copyLifeDays = settingsProvider.Settings.CopyLife;
        _logger = logger;
    }
    public async Task CleanupAsync(string archivePath, CancellationToken cancellationToken)
    {
        if (!Directory.Exists(archivePath))
        {
            _logger.Warning("Archive directory does not exist: {ArchivePath}", archivePath);
            return;
        }

        await CleanupExpiredFilesAsync(archivePath, cancellationToken);
        CleanupEmptyDirectories(archivePath, cancellationToken);
    }

    private async Task CleanupExpiredFilesAsync(string archivePath, CancellationToken cancellationToken)
    {
        var expirationDate = DateTime.UtcNow.AddDays(-_copyLifeDays);

        var files = Directory.EnumerateFiles(archivePath, "*", SearchOption.AllDirectories);

        foreach (var file in files)
        {
            if (CheckCancellation(cancellationToken))
            {
                _logger.Information("File cleanup was canceled.");
                break;
            }

            try
            {
                var fileInfo = new FileInfo(file);
                if (fileInfo.LastWriteTimeUtc <= expirationDate)
                {
                    fileInfo.Delete();
                    using (LogContext.PushProperty("LogContext", nameof(CleanupExpiredFilesAsync)))
                        _logger.Information("Deleted expired file: {File}", file);
                }
            }
            catch (Exception ex)
            {
                using (LogContext.PushProperty("LogContext", nameof(CleanupExpiredFilesAsync)))
                    _logger.Error(ex, "Error deleting file: {File}", file);
            }
        }

        await Task.CompletedTask;
    }

    private void CleanupEmptyDirectories(string directory, CancellationToken cancellationToken)
    {
        foreach (var subdirectory in Directory.GetDirectories(directory))
        {
            if (CheckCancellation(cancellationToken)) break;

            CleanupEmptyDirectories(subdirectory, cancellationToken);

            if (!Directory.EnumerateFileSystemEntries(subdirectory).Any())
            {
                try
                {
                    Directory.Delete(subdirectory);
                    _logger.Information("Deleted empty directory: {Directory}", subdirectory);
                }
                catch (Exception ex)
                {
                    using (LogContext.PushProperty("LogContext", nameof(CleanupEmptyDirectories)))
                        _logger.Error(ex, "Error deleting directory: {Directory}", subdirectory);
                }
            }
        }
    }

    private bool CheckCancellation(CancellationToken cancellationToken)
    {
        if (cancellationToken.IsCancellationRequested)
        {
            _logger.Information("Cancellation requested. Stopping cleanup operation.");
            return true;
        }
        return false;
    }
}

