using System.Linq;
using System.Configuration;
using System.IO;
using System.ServiceProcess;
using System.Configuration.Install;
using System;
using System.Threading;

namespace Sleepy
{
	public class ServiceManager
	{
		public string Folder => Path.GetDirectoryName(ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).FilePath);

		private ServiceController service;

		private bool detected = false;

		public bool IsInstalled()
		{
			if (!isPlaced())
			{
				return false;
			}

			if (findService() == null)
			{
				return false;
			}

			return true;
		}

		private ServiceController findService()
		{
			if (!detected)
			{

				if (service != null)
				{
					service.Dispose();
				}

				service = ServiceController.GetServices().Where(s => s.ServiceName == "Sleepy").FirstOrDefault();
				detected = true;

			}

			return service;
		}

		private bool isPlaced()
		{
			return File.Exists(Folder + "\\Sleepy.exe");
		}

		public void Install()
		{
			Remove();

			if (!isPlaced())
			{

				for (var i = 0; i < 10 && File.Exists(Folder + "\\Sleepy.exe"); i++)
				{
					try
					{
						File.Delete(Folder + "\\Sleepy.exe");
					}
					catch
					{
						// Escalates later.
					}
					Thread.Sleep(1000);
				}

				if (File.Exists(Folder + "\\Sleepy.exe"))
				{
					throw new Exception("Unable to delete previous version.");
				}

				Directory.CreateDirectory(Folder);
				File.Copy(System.Reflection.Assembly.GetEntryAssembly().Location, Folder + "\\Sleepy.exe");

			}

			try
			{
				ManagedInstallerClass.InstallHelper(new string[] { Folder + "\\Sleepy.exe" });
			}
			catch
			{
				throw new Exception("Service installation failed.");
			}

			detected = false;

			if (!IsInstalled())
			{
				throw new Exception("Failed to confirm service installation.");
			}

			Restart();
		}

		public void Remove()
		{
			var service = findService();

			if (service != null)
			{
				try
				{
					service.Stop();
				}
				catch
				{
					// Escalates later.
				}

				service.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(5));

				if (service.Status != ServiceControllerStatus.Stopped)
				{
					throw new Exception("Failed to stop the service.");
				}

				try
				{
					ManagedInstallerClass.InstallHelper(new string[] { "/U", Folder + "\\Sleepy.exe" });
				}
				catch
				{
					throw new Exception("Failed to remove the service.");
				}

				detected = false;

				if (IsInstalled())
				{
					throw new Exception("Failed to confirm service removal.");
				}
			}
		}

		public void Restart()
		{
			var service = findService();

			if (service != null)
			{

				if (service.Status != ServiceControllerStatus.Stopped)
				{
					service.Stop();
					service.WaitForStatus(ServiceControllerStatus.Stopped);
				}

				service.Start();
				service.WaitForStatus(ServiceControllerStatus.Running);

			}
		}
	}
}