using System;
using System.IO;
using System.Threading.Tasks;

namespace Nop.Plugin.Misc.FruitBankPlugin.Services.FileStorage
{
    /// <summary>
    /// Local file system storage provider - saves files to wwwroot/uploads
    /// </summary>
    public class LocalFileStorageProvider : IFileStorageProvider
    {
        private readonly string _baseDirectory;

        public LocalFileStorageProvider(string baseDirectory = null)
        {
            // Default to wwwroot/uploads if not specified
            _baseDirectory = baseDirectory ?? Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "uploads");

            // Ensure base directory exists
            if (!Directory.Exists(_baseDirectory))
            {
                Directory.CreateDirectory(_baseDirectory);
            }
        }

        /// <summary>
        /// Saves a file stream to local file system
        /// </summary>
        public async Task<string> SaveFileAsync(Stream fileStream, string relativePath)
        {
            if (fileStream == null)
                throw new ArgumentNullException(nameof(fileStream));

            if (string.IsNullOrWhiteSpace(relativePath))
                throw new ArgumentNullException(nameof(relativePath));

            var fullPath = Path.Combine(_baseDirectory, relativePath);
            var directory = Path.GetDirectoryName(fullPath);

            // Ensure directory exists
            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            // Save file
            using (var fileStreamOutput = new FileStream(fullPath, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                await fileStream.CopyToAsync(fileStreamOutput);
            }

            return fullPath;
        }

        /// <summary>
        /// Retrieves a file stream from local file system
        /// </summary>
        public async Task<Stream> GetFileAsync(string relativePath)
        {
            if (string.IsNullOrWhiteSpace(relativePath))
                throw new ArgumentNullException(nameof(relativePath));

            var fullPath = Path.Combine(_baseDirectory, relativePath);

            if (!File.Exists(fullPath))
                throw new FileNotFoundException($"File not found: {relativePath}", fullPath);

            // Read file into memory stream to avoid file locks
            var memoryStream = new MemoryStream();
            using (var fileStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                await fileStream.CopyToAsync(memoryStream);
            }

            memoryStream.Position = 0;
            return memoryStream;
        }

        /// <summary>
        /// Deletes a file from local file system
        /// </summary>
        public Task<bool> DeleteFileAsync(string relativePath)
        {
            if (string.IsNullOrWhiteSpace(relativePath))
                throw new ArgumentNullException(nameof(relativePath));

            var fullPath = Path.Combine(_baseDirectory, relativePath);

            if (File.Exists(fullPath))
            {
                File.Delete(fullPath);

                // Try to clean up empty directories
                CleanupEmptyDirectories(fullPath);

                return Task.FromResult(true);
            }

            return Task.FromResult(false);
        }

        /// <summary>
        /// Checks if a file exists in local file system
        /// </summary>
        public Task<bool> FileExistsAsync(string relativePath)
        {
            if (string.IsNullOrWhiteSpace(relativePath))
                return Task.FromResult(false);

            var fullPath = Path.Combine(_baseDirectory, relativePath);
            return Task.FromResult(File.Exists(fullPath));
        }

        /// <summary>
        /// Cleans up empty parent directories after file deletion
        /// </summary>
        private void CleanupEmptyDirectories(string filePath)
        {
            try
            {
                var directory = Path.GetDirectoryName(filePath);

                while (!string.IsNullOrEmpty(directory) &&
                       directory != _baseDirectory &&
                       Directory.Exists(directory) &&
                       Directory.GetFiles(directory).Length == 0 &&
                       Directory.GetDirectories(directory).Length == 0)
                {
                    Directory.Delete(directory);
                    directory = Path.GetDirectoryName(directory);
                }
            }
            catch
            {
                // Ignore cleanup errors - not critical
            }
        }
    }
}
