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

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

			var allFileInfos = new[]
			{
				tempRoot.CreateSubDirectoryFile(remoteRoot, fileSize: 1 * TemporaryDirectory.OneMebibyte),
				tempRoot.CreateSubDirectoryFile(remoteRoot, fileSize: 2 * TemporaryDirectory.OneMebibyte),
				tempRoot.CreateSubDirectoryFile(remoteRoot, fileSize: 3 * TemporaryDirectory.OneMebibyte),
				tempRoot.CreateSubDirectoryFile(remoteRoot, fileSize: 4 * TemporaryDirectory.OneMebibyte),
				tempRoot.CreateSubDirectoryFile(remoteRoot, fileSize: 5 * TemporaryDirectory.OneMebibyte)
			};

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


			var raiseException = false;
			AutoResetEvent autoReset;
			
			// Local method because of local vars.
			void OnDownloadCompleted(object s, BackgroundCopyJobEventArgs e)
			{
				DownloadCompleted(e, autoReset, allFilesToDownload.Length, allFilesTotalSize);
			}


			// Create a download job.
			using var downloadJob = BackgroundCopyManager.Jobs.Add($"{nameof(remoteRoot)} download");

			using (autoReset = new AutoResetEvent(false))
			{
				// Set job properties.
				downloadJob.Credentials.Add(BackgroundCopyJobCredentialScheme.Digest, BackgroundCopyJobCredentialTarget.Proxy, "user", "mypwd");
				downloadJob.CustomHeaders = new WebHeaderCollection() { "A1:Test", "A2:Prova" };
				downloadJob.MinimumNotificationInterval = TimeSpan.FromSeconds(1);


				// Set event handlers for job, these are weak references.
				downloadJob.Error += OnDownloadError;
				downloadJob.FileTransferred += OnDownloadFileTransferred;
				downloadJob.Completed += OnDownloadCompleted;



				// Add download file information.
				downloadJob.Files.AddRange(remoteRoot.FullName, localDirectory.FullName, allFilesToDownload);

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


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


			// Remove weak references to prevent memory leak.
			downloadJob.Completed -= OnDownloadCompleted;
			downloadJob.FileTransferred -= OnDownloadFileTransferred;
			downloadJob.Error -= OnDownloadError;


			if (raiseException)
				throw new InvalidOperationException();
		}




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


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


		private static void DownloadCompleted(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 OnDownloadFileTransferred(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}");
		}
	}
}
