using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using MusicBeePlugin.Clouseau.Core;

namespace MusicBeePlugin.Clouseau.Introspection
{
    /// <summary>
    /// Tracks sync operations (Sync_FileStart/End, Sync_FileDeleteStart/End)
    /// to provide rich context for SynchCompleted notifications.
    /// </summary>
    public class SyncTracker : IDisposable
    {
        private readonly ConcurrentDictionary<string, SyncFileOperation> _activeOperations;
        private readonly ConcurrentQueue<SyncFileOperation> _completedOperations;
        private const int MaxCompletedHistory = 200;

        private DateTime _syncStartTime;
        private int _filesSynced;
        private int _filesDeleted;
        private int _syncErrors;
        private string _currentDeviceName;
        private long _totalBytesTransferred;
        private bool _disposed;

        /// <summary>
        /// Event raised when a sync file operation completes.
        /// </summary>
        public event EventHandler<SyncFileOperation> FileOperationCompleted;

        public SyncTracker()
        {
            _activeOperations = new ConcurrentDictionary<string, SyncFileOperation>(StringComparer.OrdinalIgnoreCase);
            _completedOperations = new ConcurrentQueue<SyncFileOperation>();
            Reset();
        }

        /// <summary>
        /// Gets the number of currently active sync operations.
        /// </summary>
        public int ActiveOperationCount => _activeOperations.Count;

        /// <summary>
        /// Gets the total files synced in the current session.
        /// </summary>
        public int FilesSynced => _filesSynced;

        /// <summary>
        /// Gets the total files deleted in the current session.
        /// </summary>
        public int FilesDeleted => _filesDeleted;

        /// <summary>
        /// Gets the number of sync errors in the current session.
        /// </summary>
        public int ErrorCount => _syncErrors;

        /// <summary>
        /// Resets the sync tracking state for a new sync session.
        /// </summary>
        public void Reset()
        {
            _syncStartTime = DateTime.Now;
            _filesSynced = 0;
            _filesDeleted = 0;
            _syncErrors = 0;
            _currentDeviceName = null;
            _totalBytesTransferred = 0;
            _activeOperations.Clear();
        }

        /// <summary>
        /// Records the start of a file sync operation.
        /// Called from Sync_FileStart wrapper.
        /// </summary>
        /// <param name="sourceFile">The source file being synced.</param>
        public void OnSyncFileStart(string sourceFile)
        {
            if (string.IsNullOrEmpty(sourceFile)) return;

            var op = new SyncFileOperation
            {
                SourceFile = sourceFile,
                FileName = System.IO.Path.GetFileName(sourceFile),
                OperationType = SyncOperationType.Copy,
                StartTime = DateTime.Now
            };

            _activeOperations[sourceFile] = op;
            LogManager.Core.Trace($"Sync file start: {op.FileName}");
        }

        /// <summary>
        /// Records the end of a file sync operation.
        /// Called from Sync_FileEnd wrapper.
        /// </summary>
        /// <param name="sourceFile">The source file that was synced.</param>
        /// <param name="success">Whether the operation succeeded.</param>
        /// <param name="errorMessage">Error message if failed.</param>
        public void OnSyncFileEnd(string sourceFile, bool success, string errorMessage)
        {
            if (string.IsNullOrEmpty(sourceFile)) return;

            if (_activeOperations.TryRemove(sourceFile, out var op))
            {
                op.EndTime = DateTime.Now;
                op.Success = success;
                op.ErrorMessage = errorMessage;
                op.DurationMs = (long)(op.EndTime.Value - op.StartTime).TotalMilliseconds;

                EnqueueCompletedOperation(op);

                if (success)
                    System.Threading.Interlocked.Increment(ref _filesSynced);
                else
                    System.Threading.Interlocked.Increment(ref _syncErrors);

                LogManager.Core.Trace($"Sync file end: {op.FileName} - {(success ? "OK" : "FAIL")} ({op.DurationMs}ms)");
                OnFileOperationCompleted(op);
            }
        }

        /// <summary>
        /// Records the start of a file delete during sync.
        /// Called from Sync_FileDeleteStart wrapper.
        /// </summary>
        /// <param name="filename">The file being deleted.</param>
        public void OnSyncFileDeleteStart(string filename)
        {
            if (string.IsNullOrEmpty(filename)) return;

            var op = new SyncFileOperation
            {
                SourceFile = filename,
                FileName = System.IO.Path.GetFileName(filename),
                OperationType = SyncOperationType.Delete,
                StartTime = DateTime.Now
            };

            _activeOperations[filename] = op;
            LogManager.Core.Trace($"Sync delete start: {op.FileName}");
        }

        /// <summary>
        /// Records the end of a file delete during sync.
        /// Called from Sync_FileDeleteEnd wrapper.
        /// </summary>
        /// <param name="filename">The file that was deleted.</param>
        /// <param name="success">Whether the operation succeeded.</param>
        /// <param name="errorMessage">Error message if failed.</param>
        public void OnSyncFileDeleteEnd(string filename, bool success, string errorMessage)
        {
            if (string.IsNullOrEmpty(filename)) return;

            if (_activeOperations.TryRemove(filename, out var op))
            {
                op.EndTime = DateTime.Now;
                op.Success = success;
                op.ErrorMessage = errorMessage;
                op.DurationMs = (long)(op.EndTime.Value - op.StartTime).TotalMilliseconds;

                EnqueueCompletedOperation(op);

                if (success)
                    System.Threading.Interlocked.Increment(ref _filesDeleted);
                else
                    System.Threading.Interlocked.Increment(ref _syncErrors);

                LogManager.Core.Trace($"Sync delete end: {op.FileName} - {(success ? "OK" : "FAIL")}");
                OnFileOperationCompleted(op);
            }
        }

        /// <summary>
        /// Gets the current sync session summary.
        /// </summary>
        public SyncSessionSummary GetSessionSummary()
        {
            var now = DateTime.Now;
            return new SyncSessionSummary
            {
                StartTime = _syncStartTime,
                EndTime = now,
                DurationMs = (long)(now - _syncStartTime).TotalMilliseconds,
                FilesSynced = _filesSynced,
                FilesDeleted = _filesDeleted,
                Errors = _syncErrors,
                DeviceName = _currentDeviceName,
                TotalBytesTransferred = _totalBytesTransferred,
                ActiveOperations = _activeOperations.Count,
                RecentOperations = _completedOperations.ToArray().Skip(Math.Max(0, _completedOperations.Count - 20)).ToList()
            };
        }

        /// <summary>
        /// Sets the current device name being synced.
        /// </summary>
        /// <param name="deviceName">The device name.</param>
        public void SetDeviceName(string deviceName)
        {
            _currentDeviceName = deviceName;
        }

        /// <summary>
        /// Gets failed operations from the current session.
        /// </summary>
        public IReadOnlyList<SyncFileOperation> GetFailedOperations()
        {
            return _completedOperations.Where(op => !op.Success).ToList();
        }

        /// <summary>
        /// Gets all active operations.
        /// </summary>
        public IReadOnlyList<SyncFileOperation> GetActiveOperations()
        {
            return _activeOperations.Values.ToList();
        }

        /// <summary>
        /// Gets recent completed operations.
        /// </summary>
        /// <param name="count">Maximum number of operations to return.</param>
        public IReadOnlyList<SyncFileOperation> GetRecentOperations(int count = 50)
        {
            var all = _completedOperations.ToArray();
            return all.Skip(Math.Max(0, all.Length - count)).ToList();
        }

        private void EnqueueCompletedOperation(SyncFileOperation op)
        {
            _completedOperations.Enqueue(op);
            while (_completedOperations.Count > MaxCompletedHistory)
            {
                _completedOperations.TryDequeue(out _);
            }
        }

        protected virtual void OnFileOperationCompleted(SyncFileOperation op)
            => FileOperationCompleted?.Invoke(this, op);

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _activeOperations.Clear();
                }
                _disposed = true;
            }
        }
    }

    /// <summary>
    /// Type of sync operation.
    /// </summary>
    public enum SyncOperationType
    {
        Copy,
        Delete
    }

    /// <summary>
    /// Represents a single file sync operation.
    /// </summary>
    public class SyncFileOperation
    {
        public string SourceFile { get; set; }
        public string FileName { get; set; }
        public SyncOperationType OperationType { get; set; }
        public DateTime StartTime { get; set; }
        public DateTime? EndTime { get; set; }
        public bool Success { get; set; }
        public string ErrorMessage { get; set; }
        public long DurationMs { get; set; }
    }

    /// <summary>
    /// Summary of a sync session.
    /// </summary>
    public class SyncSessionSummary
    {
        public DateTime StartTime { get; set; }
        public DateTime EndTime { get; set; }
        public long DurationMs { get; set; }
        public int FilesSynced { get; set; }
        public int FilesDeleted { get; set; }
        public int Errors { get; set; }
        public string DeviceName { get; set; }
        public long TotalBytesTransferred { get; set; }
        public int ActiveOperations { get; set; }
        public List<SyncFileOperation> RecentOperations { get; set; }
    }
}
