using System;
using System.Management.Automation;
using PSMinIO.Utils;

namespace PSMinIO.Utils
{
    /// <summary>
    /// Manages 3-layer progress reporting for chunked file collection operations
    /// Layer 1: Collection Progress (overall files)
    /// Layer 2: Current File Progress
    /// Layer 3: Current Chunk Progress
    /// </summary>
    public class ChunkedCollectionProgressReporter
    {
        private readonly PSCmdlet _cmdlet;
        private readonly int _totalFiles;
        private readonly long _totalSize;
        private readonly DateTime _startTime;
        private readonly string _operationName;
        
        // Progress tracking
        private int _completedFiles = 0;
        private long _totalBytesTransferred = 0;
        private string _currentFileName = "";
        private long _currentFileSize = 0;
        private long _currentFileBytesTransferred = 0;
        private int _currentChunk = 0;
        private int _totalChunks = 0;
        private long _currentChunkBytesTransferred = 0;
        private long _currentChunkSize = 0;

        // Activity IDs for progress hierarchy
        private const int CollectionActivityId = 1;
        private const int FileActivityId = 2;
        private const int ChunkActivityId = 3;

        // Progress control
        private readonly long _progressUpdateInterval;
        private long _lastProgressUpdate = 0;

        /// <summary>
        /// Creates a new chunked collection progress reporter
        /// </summary>
        /// <param name="cmdlet">PowerShell cmdlet for progress reporting</param>
        /// <param name="totalFiles">Total number of files to process</param>
        /// <param name="totalSize">Total size of all files</param>
        /// <param name="operationName">Name of the operation (e.g., "Uploading", "Downloading")</param>
        /// <param name="progressUpdateInterval">Update progress every N bytes</param>
        public ChunkedCollectionProgressReporter(
            PSCmdlet cmdlet,
            int totalFiles,
            long totalSize,
            string operationName = "Processing",
            long progressUpdateInterval = 1024 * 1024) // 1MB default
        {
            _cmdlet = cmdlet;
            _totalFiles = totalFiles;
            _totalSize = totalSize;
            _operationName = operationName;
            _startTime = DateTime.Now;
            _progressUpdateInterval = progressUpdateInterval;
        }

        /// <summary>
        /// Starts processing a new file
        /// </summary>
        /// <param name="fileName">Name of the file being processed</param>
        /// <param name="fileSize">Size of the file</param>
        /// <param name="totalChunks">Total number of chunks for this file</param>
        public void StartNewFile(string fileName, long fileSize, int totalChunks)
        {
            _currentFileName = fileName;
            _currentFileSize = fileSize;
            _currentFileBytesTransferred = 0;
            _totalChunks = totalChunks;
            _currentChunk = 0;
            
            MinIOLogger.WriteVerbose(_cmdlet, "Starting {0} of file {1}/{2}: {3} ({4})",
                _operationName.ToLower(), _completedFiles + 1, _totalFiles, fileName, SizeFormatter.FormatBytes(fileSize));
            
            UpdateAllProgress();
        }

        /// <summary>
        /// Starts processing a new chunk
        /// </summary>
        /// <param name="chunkNumber">Chunk number (1-based for display)</param>
        /// <param name="chunkSize">Size of the chunk</param>
        public void StartNewChunk(int chunkNumber, long chunkSize)
        {
            _currentChunk = chunkNumber;
            _currentChunkSize = chunkSize;
            _currentChunkBytesTransferred = 0;
            
            MinIOLogger.WriteVerbose(_cmdlet, "File {0}: Starting chunk {1}/{2} ({3})",
                _currentFileName, chunkNumber, _totalChunks, SizeFormatter.FormatBytes(chunkSize));
            
            UpdateAllProgress();
        }

        /// <summary>
        /// Updates chunk progress
        /// </summary>
        /// <param name="bytesTransferred">Bytes transferred for current chunk</param>
        public void UpdateChunkProgress(long bytesTransferred)
        {
            var chunkDelta = bytesTransferred - _currentChunkBytesTransferred;
            _currentChunkBytesTransferred = bytesTransferred;
            _currentFileBytesTransferred += chunkDelta;
            _totalBytesTransferred += chunkDelta;
            
            // Only update progress if we've transferred enough bytes since last update
            if (_totalBytesTransferred - _lastProgressUpdate >= _progressUpdateInterval)
            {
                UpdateAllProgress();
                _lastProgressUpdate = _totalBytesTransferred;
            }
        }

        /// <summary>
        /// Completes the current chunk
        /// </summary>
        /// <param name="chunkETag">ETag of the completed chunk (optional)</param>
        public void CompleteChunk(string? chunkETag = null)
        {
            MinIOLogger.WriteVerbose(_cmdlet, "File {0}: Completed chunk {1}/{2}{3}", 
                _currentFileName, _currentChunk, _totalChunks, 
                !string.IsNullOrEmpty(chunkETag) ? $" - ETag: {chunkETag}" : "");

            // Mark chunk as completed (only if progress is enabled)
            if (_cmdlet.MyInvocation.BoundParameters.ContainsKey("ProgressAction") &&
                _cmdlet.MyInvocation.BoundParameters["ProgressAction"].ToString() == "SilentlyContinue")
                return;

            var chunkProgress = new ProgressRecord(ChunkActivityId, "Current Chunk", "Completed")
            {
                PercentComplete = 100,
                RecordType = ProgressRecordType.Completed,
                ParentActivityId = FileActivityId
            };
            _cmdlet.WriteProgress(chunkProgress);
        }

        /// <summary>
        /// Completes the current file
        /// </summary>
        public void CompleteFile()
        {
            _completedFiles++;
            
            var elapsed = DateTime.Now - _startTime;
            MinIOLogger.WriteVerbose(_cmdlet, "File {0}: {1} completed in {2} - Total size: {3}",
                _currentFileName, _operationName.ToLower(), elapsed.ToString(@"hh\:mm\:ss"), SizeFormatter.FormatBytes(_currentFileSize));

            // Mark file as completed (only if progress is enabled)
            if (_cmdlet.MyInvocation.BoundParameters.ContainsKey("ProgressAction") &&
                _cmdlet.MyInvocation.BoundParameters["ProgressAction"].ToString() == "SilentlyContinue")
                return;

            var fileProgress = new ProgressRecord(FileActivityId, "Current File", "Completed")
            {
                PercentComplete = 100,
                RecordType = ProgressRecordType.Completed,
                ParentActivityId = CollectionActivityId
            };
            _cmdlet.WriteProgress(fileProgress);

            // Complete chunk progress too
            CompleteChunk();
        }

        /// <summary>
        /// Completes the entire collection operation
        /// </summary>
        public void CompleteCollection()
        {
            var elapsed = DateTime.Now - _startTime;
            MinIOLogger.WriteVerbose(_cmdlet, "Completed {0} {1} files ({2}) in {3}",
                _operationName.ToLower(), _totalFiles, SizeFormatter.FormatBytes(_totalSize), elapsed.ToString(@"hh\:mm\:ss"));

            // Complete all progress records
            var collectionProgress = new ProgressRecord(CollectionActivityId, $"{_operationName} Files", "Completed")
            {
                PercentComplete = 100,
                RecordType = ProgressRecordType.Completed
            };
            _cmdlet.WriteProgress(collectionProgress);

            // Complete file progress if enabled
            if (!(_cmdlet.MyInvocation.BoundParameters.ContainsKey("ProgressAction") &&
                  _cmdlet.MyInvocation.BoundParameters["ProgressAction"].ToString() == "SilentlyContinue"))
            {
                CompleteFile();
            }
        }

        /// <summary>
        /// Reports an error for the current chunk
        /// </summary>
        /// <param name="error">Error that occurred</param>
        /// <param name="retryAttempt">Current retry attempt</param>
        /// <param name="maxRetries">Maximum retry attempts</param>
        public void ReportChunkError(Exception error, int retryAttempt, int maxRetries)
        {
            MinIOLogger.WriteVerbose(_cmdlet, "File {0}: Chunk {1}/{2} failed (attempt {3}/{4}): {5}", 
                _currentFileName, _currentChunk, _totalChunks, retryAttempt, maxRetries, error.Message);
        }

        /// <summary>
        /// Updates all progress layers
        /// </summary>
        private void UpdateAllProgress()
        {
            var elapsed = DateTime.Now - _startTime;
            var speed = elapsed.TotalSeconds > 0 ? _totalBytesTransferred / elapsed.TotalSeconds : 0;

            // Layer 1: Collection Progress (always shown)
            var collectionPercent = _totalSize > 0 ? (int)((_totalBytesTransferred * 100) / _totalSize) : 0;
            var collectionStatus = $"Files: {_completedFiles}/{_totalFiles} | " +
                                  $"Size: {SizeFormatter.FormatBytes(_totalBytesTransferred)}/{SizeFormatter.FormatBytes(_totalSize)} | " +
                                  $"Speed: {SizeFormatter.FormatBytes((long)speed)}/s | " +
                                  $"Elapsed: {elapsed:hh\\:mm\\:ss}";

            var collectionProgress = new ProgressRecord(CollectionActivityId, $"{_operationName} Files", collectionStatus)
            {
                PercentComplete = collectionPercent
            };
            _cmdlet.WriteProgress(collectionProgress);

            // Check if progress is disabled
            if (_cmdlet.MyInvocation.BoundParameters.ContainsKey("ProgressAction") &&
                _cmdlet.MyInvocation.BoundParameters["ProgressAction"].ToString() == "SilentlyContinue")
                return;

            // Layer 2: Current File Progress
            if (!string.IsNullOrEmpty(_currentFileName))
            {
                var filePercent = _currentFileSize > 0 ? (int)((_currentFileBytesTransferred * 100) / _currentFileSize) : 0;
                var fileStatus = $"File: {_currentFileName} | " +
                               $"Size: {SizeFormatter.FormatBytes(_currentFileBytesTransferred)}/{SizeFormatter.FormatBytes(_currentFileSize)}";

                var fileProgress = new ProgressRecord(FileActivityId, "Current File", fileStatus)
                {
                    PercentComplete = filePercent,
                    ParentActivityId = CollectionActivityId
                };
                _cmdlet.WriteProgress(fileProgress);
            }

            // Layer 3: Current Chunk Progress
            if (_currentChunk > 0)
            {
                var chunkPercent = _currentChunkSize > 0 ? (int)((_currentChunkBytesTransferred * 100) / _currentChunkSize) : 0;
                var chunkStatus = $"Chunk: {_currentChunk}/{_totalChunks} | " +
                                $"Size: {SizeFormatter.FormatBytes(_currentChunkBytesTransferred)}/{SizeFormatter.FormatBytes(_currentChunkSize)} | " +
                                $"Speed: {SizeFormatter.FormatBytes((long)speed)}/s";

                var chunkProgress = new ProgressRecord(ChunkActivityId, "Current Chunk", chunkStatus)
                {
                    PercentComplete = chunkPercent,
                    ParentActivityId = FileActivityId
                };
                _cmdlet.WriteProgress(chunkProgress);
            }
        }
    }
}
