using System;
using System.Collections.Generic;
using System.Data.Common;
using System.IO;
using System.Linq;
using LeafWeb.Core.Utility;
using Renci.SshNet;

namespace LeafWeb.Core.Remote
{
	public class PiscalSshClient : IPiscalClient
	{
		private const string BaseDirectory = "./LeafWeb";
		private const string RemoteScriptPath = "./piscal_manager.sh";
		private readonly PasswordConnectionInfo _connectionInfo;

		public PiscalSshClient(string connectionString)
		{
			var conn = new DbConnectionStringBuilder {ConnectionString = connectionString};

			var host = conn["host"] as string;
			var username = conn["username"] as string;
			var password = conn["password"] as string;
			_connectionInfo = new PasswordConnectionInfo(host, username, password);
		}

		private SshClient GetSshClient()
		{
			return new SshClient(_connectionInfo);
		}

		private ScpClient GetScpClient()
		{
			return new ScpClient(_connectionInfo);
		}

		public void SubmitLeafInputFile(PiscalLeafInputFile file)
		{
			var inputPath = $"{BaseDirectory}/{file.DirectoryName}/{file.Filename}";

			// copy file
			using (var scp = GetScpClient())
			using (var stream = new MemoryStream(file.Contents))
			{
				Console.WriteLine(inputPath);
				scp.Connect();
				scp.Upload(stream, inputPath);
				scp.Disconnect();
			}

			// begin processing
			using (var ssh = GetSshClient())
			{
				ssh.Connect();
				var commandText = $"{RemoteScriptPath} -d {file.DirectoryName} -f {file.Filename}";
				var exeCommand = ssh.CreateCommand(commandText);
				exeCommand.Execute();
				ssh.Disconnect();

				Console.Write(exeCommand.Result);

				if (exeCommand.ExitStatus != 0)
					throw new PiscalClientException(exeCommand.Error);
			}
		}

		public PiscalStatus GetLeafInputStatus(PiscalLeafInputFile file)
		{
			using (var ssh = GetSshClient())
			{
				ssh.Connect();
				var commandText = $"{RemoteScriptPath} -d {file.DirectoryName} -s";
				var exeCommand = ssh.CreateCommand(commandText);
				exeCommand.Execute();
				ssh.Disconnect();

				Console.Write(exeCommand.Result);
			}
			return PiscalStatus.Success;
		}

		public IEnumerable<PiscalLeafOutputFile> RetrieveLeafInputResult(PiscalLeafInputFile file)
		{
			var outputDirectory = $"{BaseDirectory}/{file.DirectoryName}";

			string[] filenames;

			// get output files
			using (var ssh = GetSshClient())
			{
				ssh.Connect();
				var commandText = $"ls -1 {outputDirectory}";
				var lsCommand = ssh.CreateCommand(commandText);
				lsCommand.Execute();
				ssh.Disconnect();

				filenames = lsCommand.Result.SplitNewLine().Where(s => s.Length > 0).Select(s => s.Trim()).ToArray();
				Console.Write(lsCommand.Result);
			}

			using (var scp = GetScpClient())
			{
				scp.Connect();
				foreach (var filename in filenames)
				{
					using (var stream = new MemoryStream())
					{
						var filePath = $"{BaseDirectory}/{file.DirectoryName}/{filename}";
						scp.Download(filePath, stream);
						yield return new PiscalLeafOutputFile {Contents = stream.ToArray(), Filename = filename};
					}
				}

				scp.Disconnect();
			}
		}
	}
}