using Serilog;

namespace Phantom.Utils.Runtime; 

public abstract class CancellableBackgroundTask {
	private readonly CancellationTokenSource cancellationTokenSource = new ();

	protected ILogger Logger { get; }
	protected CancellationToken CancellationToken { get; }

	private readonly TaskManager taskManager;
	private readonly string taskName;
	
	protected CancellableBackgroundTask(ILogger logger, TaskManager taskManager, string taskName) {
		this.Logger = logger;
		this.CancellationToken = cancellationTokenSource.Token;
		
		this.taskManager = taskManager;
		this.taskName = taskName;
	}

	protected void Start() {
		taskManager.Run(taskName, Run);
	}

	private async Task Run() {
		Logger.Debug("Task started.");

		try {
			await RunTask();
		} catch (OperationCanceledException) {
			// Ignore.
		} catch (Exception e) {
			Logger.Fatal(e, "Caught exception in task.");
		} finally {
			cancellationTokenSource.Dispose();
			Dispose();
			Logger.Debug("Task stopped.");
		}
	}
	
	protected abstract Task RunTask();

	protected virtual void Dispose() {}

	public void Stop() {
		try {
			cancellationTokenSource.Cancel();
		} catch (ObjectDisposedException) {
			// Ignore.
		}
	}
}