@using Ardalis.GuardClauses
@using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence

@implements IDisposable

<TerminalDisplay @ref="@_terminalDisplayRef"/>

@code {

	[Parameter, EditorRequired]
    public SharpIdeProjectModel Project { get; set; } = null!;

	[Parameter]
	public EventCallback<SharpIdeProjectModel> OnProjectStarted { get; set; }

	private TerminalDisplay _terminalDisplayRef = null!;

	protected override async Task OnInitializedAsync()
	{
		Project.ProjectStartedRunning.Subscribe(OnProjectStartedRunning);
		// This event may/will be raised before the component is initialized, so we call OnProjectStartedRunning directly, for the first render.
		await OnProjectStartedRunning();
	}

	private async Task OnProjectStartedRunning()
	{
		Guard.Against.Null(Project);
		Guard.Against.Null(Project.RunningOutputChannel, nameof(Project.RunningOutputChannel));

		_ = Task.Run(async () =>
		{
			try
			{
				if (_terminalDisplayRef is not null) await _terminalDisplayRef.Clear();
				await InvokeAsync(async () => await OnProjectStarted.InvokeAsync(Project));
				await foreach (var log in Project.RunningOutputChannel.Reader.ReadAllAsync().ConfigureAwait(false))
				{
					// Better hope you don't get a log until we get the component ref lol
					await _terminalDisplayRef.Write(log).ConfigureAwait(false);
				}
			}
			catch (Exception e) when (e is not OperationCanceledException)
			{
				await DispatchExceptionAsync(e);
			}
		});
	}

	public void Dispose() => Project.ProjectStartedRunning.Unsubscribe(OnProjectStartedRunning);
}
