/*
 * Copyright (c) 2025 ETH Zürich, IT Services
 * 
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

using System;
using SafeExamBrowser.Configuration.Contracts;
using SafeExamBrowser.Core.Contracts.OperationModel;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Settings.Security;
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
using SafeExamBrowser.UserInterface.Contracts.Windows;

namespace SafeExamBrowser.Runtime.Responsibilities
{
	internal class SessionResponsibility : RuntimeResponsibility
	{
		private readonly AppConfig appConfig;
		private readonly IMessageBox messageBox;
		private readonly IRuntimeWindow runtimeWindow;
		private readonly IRepeatableOperationSequence sessionSequence;
		private readonly Action shutdown;
		private readonly IText text;

		internal SessionResponsibility(
			AppConfig appConfig,
			ILogger logger,
			IMessageBox messageBox,
			RuntimeContext runtimeContext,
			IRuntimeWindow runtimeWindow,
			IRepeatableOperationSequence sessionSequence,
			Action shutdown,
			IText text) : base(logger, runtimeContext)
		{
			this.appConfig = appConfig;
			this.messageBox = messageBox;
			this.runtimeWindow = runtimeWindow;
			this.sessionSequence = sessionSequence;
			this.shutdown = shutdown;
			this.text = text;
		}

		public override void Assume(RuntimeTask task)
		{
			switch (task)
			{
				case RuntimeTask.StartSession:
					StartSession();
					break;
				case RuntimeTask.StopSession:
					StopSession();
					break;
			}
		}

		private void StartSession()
		{
			runtimeWindow.Show();
			runtimeWindow.BringToForeground();
			runtimeWindow.ShowProgressBar = true;

			Logger.Info(AppendDivider("Session Start Procedure"));

			if (SessionIsRunning)
			{
				Context.Responsibilities.Delegate(RuntimeTask.DeregisterSessionEvents);
			}

			var result = SessionIsRunning ? sessionSequence.TryRepeat() : sessionSequence.TryPerform();

			if (result == OperationResult.Success)
			{
				Logger.Info(AppendDivider("Session Running"));

				HandleSessionStartSuccess();
			}
			else if (result == OperationResult.Failed)
			{
				Logger.Info(AppendDivider("Session Start Failed"));

				HandleSessionStartFailure();
			}
			else if (result == OperationResult.Aborted)
			{
				Logger.Info(AppendDivider("Session Start Aborted"));

				HandleSessionStartAbortion();
			}
		}

		private void StopSession()
		{
			runtimeWindow.Show();
			runtimeWindow.BringToForeground();
			runtimeWindow.ShowProgressBar = true;

			Logger.Info(AppendDivider("Session Stop Procedure"));

			Context.Responsibilities.Delegate(RuntimeTask.DeregisterSessionEvents);

			var success = sessionSequence.TryRevert() == OperationResult.Success;

			if (success)
			{
				Logger.Info(AppendDivider("Session Terminated"));
			}
			else
			{
				Logger.Info(AppendDivider("Session Stop Failed"));
			}
		}

		private void HandleSessionStartSuccess()
		{
			Context.Responsibilities.Delegate(RuntimeTask.RegisterSessionEvents);

			runtimeWindow.ShowProgressBar = false;
			runtimeWindow.ShowLog = Session.Settings.Security.AllowApplicationLogAccess;
			runtimeWindow.TopMost = Session.Settings.Security.KioskMode != KioskMode.None;
			runtimeWindow.UpdateStatus(TextKey.RuntimeWindow_ApplicationRunning);

			//if (Session.Settings.Security.KioskMode == KioskMode.DisableExplorerShell)
			//{
			//	runtimeWindow.Hide();
			//}
			runtimeWindow.Hide();
		}

		private void HandleSessionStartFailure()
		{
			var message = AppendLogFilePaths(appConfig, text.Get(TextKey.MessageBox_SessionStartError));
			var title = text.Get(TextKey.MessageBox_SessionStartErrorTitle);

			if (SessionIsRunning)
			{
				StopSession();

				messageBox.Show(message, title, icon: MessageBoxIcon.Error, parent: runtimeWindow);

				Logger.Info("Terminating application...");
				shutdown.Invoke();
			}
			else
			{
				messageBox.Show(message, title, icon: MessageBoxIcon.Error, parent: runtimeWindow);
			}
		}

		private void HandleSessionStartAbortion()
		{
			if (SessionIsRunning)
			{
				Context.Responsibilities.Delegate(RuntimeTask.RegisterSessionEvents);

				runtimeWindow.ShowProgressBar = false;
				runtimeWindow.UpdateStatus(TextKey.RuntimeWindow_ApplicationRunning);
				runtimeWindow.TopMost = Session.Settings.Security.KioskMode != KioskMode.None;

				//if (Session.Settings.Security.KioskMode == KioskMode.DisableExplorerShell)
				//{
				//	runtimeWindow.Hide();
				//}
				runtimeWindow.Hide();

				Context.ClientProxy.InformReconfigurationAborted();
			}
		}

		private string AppendDivider(string message)
		{
			var dashesLeft = new string('-', 48 - message.Length / 2 - message.Length % 2);
			var dashesRight = new string('-', 48 - message.Length / 2);

			return $"### {dashesLeft} {message} {dashesRight} ###";
		}
	}
}
