using NUnit.Framework;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;

namespace Vanara.IO.Tests
{
	partial class BackgroundCopyTests
	{
		[Test]
		public void UploadJobTest()
		{
			using var tempRoot = new TemporaryDirectory();
			DirectoryInfo remoteRoot; remoteRoot = tempRoot.CreateSubDirectory(nameof(remoteRoot));
			DirectoryInfo localDirectory; localDirectory = tempRoot.CreateSubDirectory(nameof(localDirectory));

			var allFileInfos = new[]
			{
				tempRoot.CreateSubDirectoryFile(localDirectory, fileSize: 5 * TemporaryDirectory.OneMebibyte)
			};

			var allFilesTotalSize = allFileInfos.Select(fi => fi.Length).Sum();
			var allFilesToUpload = allFileInfos.Select(fi => fi.Name).ToArray();


			var raiseException = false;
			AutoResetEvent autoReset;

			// Local method because of local vars.
			void OnUploadCompleted(object s, BackgroundCopyJobEventArgs e)
			{
				UploadCompleted(e, autoReset, allFilesToUpload.Length, allFilesTotalSize);
			}


			// Create an upload job.
			using var uploadJob = BackgroundCopyManager.Jobs.Add($"{nameof(remoteRoot)} upload", jobType: BackgroundCopyJobType.Upload);

			using (autoReset = new AutoResetEvent(false))
			{
				// Set event handlers for job, these are weak references.
				uploadJob.Error += OnUploadError;
				uploadJob.FileTransferred += OnUploadFileTransferred;
				uploadJob.Completed += OnUploadCompleted;


				// Add upload file information.
				var fileToUpload = Path.Combine(remoteRoot.FullName, allFileInfos[0].Name);

				uploadJob.Files.Add(fileToUpload, allFileInfos[0].FullName);

				// Start (resume) the job.
				uploadJob.Resume();


				// Block thread and wait.
				raiseException = !autoReset.WaitOne(TimeSpan.FromSeconds(10));
			}


			// Remove weak references to prevent memory leak.
			uploadJob.Completed -= OnUploadCompleted;
			uploadJob.FileTransferred -= OnUploadFileTransferred;
			uploadJob.Error -= OnUploadError;


			if (raiseException)
				throw new InvalidOperationException();
		}




		// Better performance when event methods are defined seperately, preferably static.


		private static void OnUploadError(object s, BackgroundCopyJobEventArgs e)
		{
			throw e.Job.LastError;
		}


		private static void UploadCompleted(BackgroundCopyJobEventArgs e, AutoResetEvent autoResetEvent, long totalFiles, long totalBytes)
		{
			var job = e.Job;

			job.Complete();

			Assert.AreEqual(totalFiles, job.Progress.FilesTotal);
			Assert.AreEqual(totalBytes, job.Progress.BytesTransferred);


			// Enable: Debug > Options > Debugging > General: Redirect all Output Window text to the Immediate Window
			Debug.WriteLine($"Completed job: {job.DisplayName} | Total files: {job.Progress.FilesTotal:N0} | Bytes: {job.Progress.BytesTotal:N0}");


			autoResetEvent.Set();
		}


		private static void OnUploadFileTransferred(object s, BackgroundCopyFileTransferredEventArgs e)
		{
			var fileInfo = e.FileInfo;

			// Enable: Debug > Options > Debugging > General: Redirect all Output Window text to the Immediate Window
			Debug.WriteLine($"Transferred {fileInfo.BytesTransferred:N0} bytes | File: {fileInfo.LocalFilePath}");
		}
	}
}
