@using SharpIDE.Application.Features.Analysis
@using SharpIDE.Application.Features.Build
@using SharpIDE.Application.Features.Events
@using SharpIDE.Application.Features.SolutionDiscovery
@using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence
@using SharpIDE.Photino.Models
@inherits LayoutComponentBase

@inject IDialogService DialogService
@inject BuildService BuildService
@inject AppState AppState
@inject RoslynAnalysis RoslynAnalysis

<MudLayout Style="height: 100%">
	<MudAppBar Dense="true" Gutters="false" Class="px-2">
		<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
			<MudButton Style="min-width: 20px;">
				<MudIcon Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit"/>
			</MudButton>
			<MudButton OnClick="@LoadSolutionFromInteractivePicker" Style="min-width: 20px;">
				<MudIcon Icon="@Icons.Material.Filled.FolderOpen" Color="Color.Inherit"/>
			</MudButton>
			<MudButtonGroup OverrideStyles="false">
				<MudButton Variant="Variant.Filled"   Size="Size.Small" Color="Color.Primary" Disabled="@IsRunningMsBuildJob()" OnClick="@BuildSolution">Build</MudButton>
				<MudButton Variant="Variant.Outlined" Size="Size.Small" Color="Color.Primary" Disabled="@IsRunningMsBuildJob()" OnClick="@RebuildSolution">Rebuild</MudButton>
				<MudButton Variant="Variant.Outlined" Size="Size.Small" Color="Color.Primary" Disabled="@IsRunningMsBuildJob()" OnClick="@CleanSolution">Clean</MudButton>
				<MudButton Variant="Variant.Outlined" Size="Size.Small" Color="Color.Primary" Disabled="@IsRunningMsBuildJob()" OnClick="@RestoreSolution">Restore</MudButton>
			</MudButtonGroup>
			<MudButton OnClick="@CancelBuild" Disabled="@(_cancellationTokenSource is null or { IsCancellationRequested: true })" Style="min-width: 20px;">
				<MudIcon Disabled="@(_cancellationTokenSource is null or { IsCancellationRequested: true })" Icon="@Icons.Material.Filled.Cancel" Color="Color.Error"/>
			</MudButton>
		</MudStack>
		<MudSpacer/>
		<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
			<MudButton Style="min-width: 20px;" OnClick="@OpenSettingsDialog">
				<MudIcon Icon="@Icons.Material.Filled.Settings" Size="Size.Medium" Color="Color.Default"/>
			</MudButton>
			@if (_solutionModel is not null)
			{
				<RunPopover SolutionModel="@_solutionModel" />
			}
			else
			{
				<MudButton Disabled="true" Style="min-width: 20px">
					<MudIcon Icon="@Icons.Material.Filled.PlayArrow" Disabled="true" Size="Size.Medium" Color="Color.Default"/>
				</MudButton>
			}
		</MudStack>
	</MudAppBar>

	<MudMainContent Style="height: 100%">
		<MudStack Style="height: 100%; overflow: hidden" Row="true" Spacing="0" StretchItems="StretchItems.Middle">
			<MudPaper Elevation="6" Height="100%" Style="background-color: var(--mud-palette-appbar-background); z-index: 1200;">
				<MudStack AlignItems="AlignItems.Center" Spacing="1" Style="padding: 4px; height: 100%">
					<SidebarIconButton Icon="@Icons.Material.Outlined.FolderOpen" Text="Explorer" OnClick="@DrawerToggle" Selected="@_drawerOpen" />
					<MudSpacer />
					<SidebarIconButton Icon="@Icons.Material.Outlined.ErrorOutline" Text="Problems" OnClick="@ClickProblemsPanel" Selected="@(_selectedBottomPanel is BottomPanelType.Problems)" />
					<SidebarIconButton Icon="@Icons.Material.Outlined.PlayArrow" Text="Run" OnClick="@ClickRunPanel" Selected="@(_selectedBottomPanel is BottomPanelType.Run)" />
					<SidebarIconButton Icon="@Icons.Material.Outlined.BugReport" Text="Debug" Selected="false"/>
					<SidebarIconButton Icon="@Icons.Material.Outlined.Terminal" Text="Build" OnClick="@ClickBuildPanel" Selected="@(_selectedBottomPanel is BottomPanelType.Build)" />
				</MudStack>
			</MudPaper>
			<div>
				<MudPaper Elevation="0" Height="@MainContentHeight" Style="overflow:hidden; position:relative;">
					<MudDrawerContainer Style="height: 100%" Class="mud-height-full">
						<MudDrawer @bind-Open="@_drawerOpen" Style="height: 100%" Width="400px" Fixed="false" Variant="@DrawerVariant.Persistent">
							@if (_solutionFilePath is not null)
							{
								<SolutionExplorer @bind-SelectedNode="@_selectedNode" @bind-SelectedNode:after="@AfterSelectedNodeChanged" SolutionModel="@_solutionModel"/>
							}
						</MudDrawer>
						<div class="d-flex justify-center align-center mud-height-full" style="flex-direction: row">
							<MudContainer Style="height: 100%" MaxWidth="MaxWidth.False" Class="ma-0 pa-0">
							@if (_solutionFilePath is not null)
							{
								<CodeViewer SelectedFile="@_selectedFile"/>
							}
							</MudContainer>
						</div>
					</MudDrawerContainer>
				</MudPaper>
				<div class="mud-elevation-24" style="height: 30%; position:relative">
					@if (_solutionFilePath is not null)
					{
						<DisplayNoneComponent Visible="@(_selectedBottomPanel is BottomPanelType.Problems)">
							<ProblemsPanel SolutionModel="@_solutionModel" OnFileSelected="@OnProblemSelected" />
						</DisplayNoneComponent>
						<DisplayNoneComponent Visible="@(_selectedBottomPanel is BottomPanelType.Run)">
							<RunPanel SolutionModel="@_solutionModel"/>
						</DisplayNoneComponent>
						<DisplayNoneComponent Visible="@(_selectedBottomPanel is BottomPanelType.Build)">
							<BuildOutputDisplay/>
						</DisplayNoneComponent>
					}
				</div>
			</div>

			<div>@* fake for StretchItems.Middle *@</div>
		</MudStack>
	</MudMainContent>
</MudLayout>

@code {
	private bool _drawerOpen = true;
	private bool _bottomDrawerOpen = false;
	private void DrawerToggle() => _drawerOpen = !_drawerOpen;

	private string? _solutionFilePath;
	private SharpIdeSolutionModel? _solutionModel;
	private ISharpIdeNode? _selectedNode;
	private SharpIdeFile? _selectedFile;
	private BottomPanelType? _selectedBottomPanel = null;

	private string MainContentHeight => _bottomDrawerOpen ? "70%" : "100%";

	private void ClickProblemsPanel() => SwitchOrToggleBottomPanel(BottomPanelType.Problems);
	private void ClickRunPanel() => SwitchOrToggleBottomPanel(BottomPanelType.Run);
	private void ClickBuildPanel() => SwitchOrToggleBottomPanel(BottomPanelType.Build);
	private void SwitchOrToggleBottomPanel(BottomPanelType bottomPanelType)
	{
		if (_selectedBottomPanel == bottomPanelType)
		{
			_selectedBottomPanel = null;
			_bottomDrawerOpen = false;
		}
		else
		{
			_selectedBottomPanel = bottomPanelType;
			_bottomDrawerOpen = true;
		}
	}
	private void SelectBottomPanel(BottomPanelType bottomPanelType)
	{
		_selectedBottomPanel = bottomPanelType;
		_bottomDrawerOpen = true;
	}

	protected override async Task OnInitializedAsync()
	{
		GlobalEvents.Instance = new GlobalEvents();
		await LoadSolutionFromInteractivePicker(AppState.IdeSettings.AutoOpenLastSolution);
		GlobalEvents.Instance.StartedRunningProject.Subscribe(OnStartedRunningProject);
	}

	private void OnProblemSelected(SharpIdeFile file)
	{
		_selectedFile = file;
		_selectedNode = file;
		var parent = _selectedFile.Parent;
		parent.Expanded = true;
		while (parent is IChildSharpIdeNode childNode)
		{
			if (childNode is not IExpandableSharpIdeNode expandableParent) throw new InvalidOperationException("Parent node must implement IExpandableSharpIdeNode");
			expandableParent.Expanded = true;
			parent = childNode.Parent;
		}
		if (parent is not SharpIdeSolutionModel solutionModel) throw new InvalidOperationException("Parent node must be a SharpIdeSolutionModel");
		solutionModel.Expanded = true;
		StateHasChanged();
	}

	private void AfterSelectedNodeChanged()
	{
		if (_selectedNode is SharpIdeFile file)
		{
			_selectedFile = file;
		}
	}

	private async Task OnStartedRunningProject()
	{
		SelectBottomPanel(BottomPanelType.Run);
		await InvokeAsync(StateHasChanged);
	}

	private async Task LoadSolutionFromInteractivePicker() => await LoadSolutionFromInteractivePicker(false);
	private async Task LoadSolutionFromInteractivePicker(bool autoOpenLastSolution)
	{
		var dialogRef = await DialogService.ShowAsync<SolutionPickerDialog>("Open Solution",new DialogParameters { [nameof(SolutionPickerDialog.AutoOpenLastSolution)] = autoOpenLastSolution }, new DialogOptions { FullWidth = true, MaxWidth = MaxWidth.Medium, BackdropClick = false });
		var result = await dialogRef.Result;
		if (result is null) throw new InvalidOperationException("Dialog result is null");
		if (result.Canceled) throw new OperationCanceledException("Dialog was canceled");
		var solutionFilePath = (string)result.Data!;
		_solutionFilePath = solutionFilePath;

		var solutionModel = await VsPersistenceMapper.GetSolutionModel(_solutionFilePath);
		_solutionModel = solutionModel;
		RoslynAnalysis.StartSolutionAnalysis(solutionModel);
	}

	private CancellationTokenSource? _cancellationTokenSource = null!;
	private async Task BuildSolution() => await MsBuildSolution(BuildType.Build);
	private async Task RebuildSolution() => await MsBuildSolution(BuildType.Rebuild);
	private async Task CleanSolution() => await MsBuildSolution(BuildType.Clean);
	private async Task RestoreSolution() => await MsBuildSolution(BuildType.Restore);
	private async Task MsBuildSolution(BuildType buildType)
	{
		if (AppState.IdeSettings.OpenTerminalOnBuildRebuildRestore) SelectBottomPanel(BottomPanelType.Build);
		_cancellationTokenSource = new CancellationTokenSource();
		await BuildService.MsBuildAsync(_solutionFilePath!, buildType, _cancellationTokenSource.Token);
		_cancellationTokenSource = null;
	}
	private async Task CancelBuild() => await _cancellationTokenSource!.CancelAsync();
	private bool IsRunningMsBuildJob() => _cancellationTokenSource is not null;

	private async Task OpenSettingsDialog()
	{
		var dialogRef = await DialogService.ShowAsync<IdeSettingsDialog>("SharpIDE Settings", new DialogOptions { MaxWidth = MaxWidth.Medium, CloseButton = true });
	}
}
