<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="using:System.Collections.Generic"
        xmlns:vm="using:DodoSSH.Client.Shell.ViewModels"
        xmlns:views="using:DodoSSH.Client.App.Views"
        x:Class="DodoSSH.Client.App.Views.MainWindow"
        x:DataType="vm:MainWindowViewModel"
        Title="DodoSSH"
        Icon="/Assets/dodossh.ico"
        Width="1180"
        Height="760"
        MinWidth="1016"
        MinHeight="574"
        Background="{StaticResource Canvas}"
        SystemDecorations="BorderOnly"
        Focusable="True">

  <!--
    The shell window: a titlebar it draws itself, a sidebar, a tab strip, one surface at a time, and a
    status bar.

    THE MINIMUM GREW, and it grew by exactly what v2 added rather than by a round number somebody liked.
    The sidebar went from 54 pixels to 190 and the chrome from 72 tall to 86, so 880x560 became 1016x574 —
    which leaves every screen the same 826x464 it was designed against. That is the whole point of moving
    it: the layout suite's premise is that everything fits at the minimum, and four of the tables stop
    fitting at 690 wide. Widening the sidebar without widening the window would have quietly broken them
    somewhere nobody was looking.

    Windows is asked for a resize border and nothing else, so TitleBar does the dragging, the maximising and
    the closing. That is a real cost, and the reason it is paid is that a stock grey system bar above a
    near-black application is the one part of the window that would look borrowed.

    SystemDecorations="BorderOnly" rather than extending the client area under the system chrome, which is
    what this tried first and is measurably wrong on Avalonia 12: ExtendClientAreaChromeHints is gone from
    that version, so extending leaves the caption buttons and the window title drawn on top of this
    window's own — two sets of minimise/maximise/close, and "DodoSSH" printed twice, overlapping. BorderOnly
    removes the caption and keeps the resize border and the drop shadow, which is the half of the system
    chrome worth having.

    TWO SURFACES, ONE RECTANGLE.

    The tab strip is above everything the nav rail leads to, so a terminal opened from any screen stays
    visible and reachable from every other one. What that costs is that the terminal and the pages now share
    the area beneath the strip, and exactly one of them may occupy it. That is the whole of ShellSurface: an
    enum rather than two flags, so there is no way to write the state where both are showing.

    THE OCCLUSION RULE, which every arrangement in this file obeys.

    NativeWebView hosts a real Win32 child window through NativeControlHost, and a child window composites
    above everything the parent paints — so no sibling in this visual tree can cover it, whatever the
    z-order says. Layering a screen over it leaves that screen sliced at the WebView's left edge with its
    buttons unreachable, which this window has shipped once already.

    So anything that would occupy the terminal's rectangle collapses the terminal instead, and
    IsTerminalShowing is the one place that decision is made: a locked vault, the page area, or the
    quick-connect palette. Collapsing is safe, and cheaply so — NativeControlHost creates the native
    control when the control is attached to the visual tree, not when it is laid out or shown, so WebView2
    still starts, still loads the page and still lets the renderer attach its socket while it is false. It
    only swaps ShowInBounds for HideWithSize, and flipping it back re-pushes the bounds.

    Note where IsShowingPages is bound: on the one Panel that holds every screen, not on each screen. That
    is what makes the rule hard to break rather than merely documented — a sixth screen added inside that
    Panel cannot forget to collapse, because it is not the thing doing the collapsing. Its own IsVisible
    only chooses between the pages.

    Two nearby alternatives are wrong. Removing the control from the tree instead — conditional content, a
    template swap — detaches it, and detaching destroys the native control and the whole WebView2 process
    tree, so every unlock would pay a cold start. Hoisting the binding to an ancestor looks tidier and is
    unverified: NativeControlHost does watch ancestors, but NativeWebView's own bounds-and-scaling re-push
    fires only for its own IsVisible.
  -->

  <Grid RowDefinitions="Auto,*,Auto">

    <views:TitleBar Grid.Row="0" />

    <Panel Grid.Row="1">

      <!-- The unlocked application. -->
      <Grid RowDefinitions="Auto,*" IsVisible="{Binding IsUnlocked}">

        <!--
          ◆ THE STRIP IS ABOVE THE RAIL, and it used to be beside it.

          It was the other way round for a reason that stopped being true: while every tab was a terminal,
          the strip navigated only the area to the right of a full-height rail, and putting it over the rail
          would have been a row of tabs above a column of destinations they had nothing to do with.

          The three fixed tabs are what changed that. The rail is now one tab's contents rather than the
          window's own furniture — Vaults owns it, SFTP and S3 do not have it, and a terminal does not
          either — so a rail drawn beside the strip would outrank the thing that decides whether it is
          showing at all. Above and full width is the arrangement that matches what selects what.
        -->
        <views:TerminalTabs Grid.Row="0" />

        <Grid Grid.Row="1" ColumnDefinitions="Auto,*">

          <!--
            The Vaults tab's own navigation, and it collapses with that tab. Its width is 190 either way, so
            SFTP, S3 and a terminal each get the full window rather than the 826 a page gets.
          -->
          <views:NavRail Grid.Column="0" IsVisible="{Binding IsVaultsTab}" />

          <Panel Grid.Column="1">

            <!-- ============ THE PAGES ============ -->
            <Panel IsVisible="{Binding IsShowingPages}">

              <!--
                Wrapped, like every other screen here. It used to be bound directly — its data context was
                the shell's, so IsHostsScreen resolved on the same element — and that was only so it could
                hand the vault to the host sidebar from inside its own markup. The sidebar is gone and the
                drawer that replaced it is a plain child, so the screen takes the vault like the rest and
                its visibility goes on the wrapper.
              -->
              <Panel IsVisible="{Binding IsHostsScreen}">
                <views:HostsScreen x:Name="HostsPane" DataContext="{Binding Vault}" />
              </Panel>

              <!-- ============ SFTP ============ -->
              <!--
                Inside this Panel although it is a tab rather than a rail screen, and that is not an
                oversight. IsShowingPages means "the Avalonia page area, not the WebView", which is the
                occlusion question and is true of all three fixed tabs; which of them is showing is the
                separate question each child below answers. Keeping the two apart is what lets the terminal
                stay collapsed under one rule rather than under four.

                What differs from a rail screen is only the rail: NavRail collapses on IsVaultsTab above, so
                this screen is laid out at the full window width.

                Wrapped rather than bound directly, for the same reason the vault screen is: this element's
                visibility is the shell's business and its data context is the transfers view model, and
                putting both on one element resolves IsVisible against that view model, where
                IsTransfersScreen does not exist.
              -->
              <Panel IsVisible="{Binding IsTransfersScreen}">
                <views:TransfersScreen DataContext="{Binding Transfers}" />
              </Panel>

              <!-- ============ S3 ============ -->
              <!--
                The same screen as SFTP above, over the same view model, because an object store and an
                SFTP host are both an IRemoteFileStore and everything below the picker was written once.
                What differs is which picker is offered, and that is decided by the destination rather than
                by a toggle inside the screen — see ShowFiles, and the tab in the strip that calls it.
              -->
              <Panel IsVisible="{Binding IsBucketsScreen}">
                <views:TransfersScreen DataContext="{Binding Transfers}" />
              </Panel>

              <!-- ============ KEYCHAIN ============ -->
              <!--
                Wrapped rather than bound directly, for the reason the vault column always was: this
                element's visibility is the shell's business and its data context is the vault, and put both
                on one element and IsVisible resolves against the vault as well, where IsVaultScreen does
                not exist.
              -->
              <Panel IsVisible="{Binding IsVaultScreen}">
                <views:VaultScreen x:Name="VaultPane" DataContext="{Binding Vault}" />
              </Panel>

              <!-- ============ HOST KEYS ============ -->
              <!--
                Wrapped, like the two above and for the same reason: its data context is the screen's own
                view model, where IsKnownHostsScreen does not exist.
              -->
              <Panel IsVisible="{Binding IsKnownHostsScreen}">
                <views:KnownHostsScreen x:Name="PinsPane" DataContext="{Binding KnownHostsScreen}" />
              </Panel>

              <!-- ============ SNIPPETS ============ -->
              <!-- Wrapped, like the others whose data context is their own view model. -->
              <Panel IsVisible="{Binding IsSnippetsScreen}">
                <views:SnippetsScreen x:Name="SnippetsPane" DataContext="{Binding SnippetsScreen}" />
              </Panel>

              <!-- ============ LOGS ============ -->
              <!-- Wrapped, like the others whose data context is their own view model. -->
              <Panel IsVisible="{Binding IsLogsScreen}">
                <views:LogsScreen x:Name="LogsPane" DataContext="{Binding LogsScreen}" />
              </Panel>

              <!-- ============ TEAM ============ -->
              <!--
                Wrapped, for the reason the vault and transfers screens are: the visibility is the shell's
                business and the data context is the teams view model, and both on one element would resolve
                IsTeamScreen against a type that does not have it.
              -->
              <Panel IsVisible="{Binding IsTeamScreen}">
                <views:TeamsScreen DataContext="{Binding Teams}" />
              </Panel>

              <!-- ============ PREFERENCES ============ -->
              <views:PreferencesScreen IsVisible="{Binding IsPreferencesScreen}" />

              <!-- ============ IMPORT ============ -->
              <!--
                Reached from preferences rather than from the rail; see ShellScreen.Import. Wrapped, like
                the others whose data context is their own view model.
              -->
              <Panel IsVisible="{Binding IsImportScreen}">
                <views:ImportScreen x:Name="ImportPane" DataContext="{Binding ImportScreen}" />
              </Panel>

            </Panel>

            <!--
              The other thing that can be in the terminal's rectangle: a tab whose session does not exist
              yet, or never will. Exclusive with the WebView below by construction — a selected tab either
              has a session or it does not — which is what makes drawing it here safe under the occlusion
              rule, the same way the page area is. See ConnectingCard.axaml.
            -->
            <views:ConnectingCard x:Name="ConnectingPane"
                                  IsVisible="{Binding IsConnectingShowing, FallbackValue=False}" />

            <!--
              One WebView hosting every terminal. Not one per tab: each WebView2 is a separate browser
              process tree, so twenty tabs would cost twenty of them.

              A sibling of the page area rather than a child of any screen, which is the structural half of
              the tab rework: the terminal belongs to the window now, not to the hosts screen.

              FallbackValue, because a compiled binding with no DataContext yields UnsetValue, IsVisible
              then falls back to its default of true, and the occlusion comes back silently. Not reachable
              at runtime — the DataContext is set before the window is shown — but it is what the previewer
              does.
            -->
            <NativeWebView x:Name="Terminal"
                           IsVisible="{Binding IsTerminalShowing, FallbackValue=False}" />

          </Panel>
        </Grid>
      </Grid>

      <!--
        Setup and unlock. Later in the Panel, so it is above the application content in Avalonia's z-order —
        which covers Avalonia-drawn content and nothing else. The terminal is collapsed rather than covered;
        see the occlusion rule above.
      -->
      <Border Background="{StaticResource Canvas}" IsVisible="{Binding !IsUnlocked}">
        <Panel>

          <Border Classes="card" IsVisible="{Binding IsStarting}">
            <StackPanel Spacing="10">
              <TextBlock Classes="heading" Text="DodoSSH" />
              <TextBlock Classes="hint" Text="{Binding StatusMessage}" />
            </StackPanel>
          </Border>

          <Border Classes="card" IsVisible="{Binding IsNeedingServer}">
            <StackPanel Spacing="12">
              <TextBlock Classes="heading" Text="Connect to your server" />
              <TextBlock Classes="hint"
                         Text="One address is all this needs. The identity provider, the client id and the scopes all come from the server itself." />
              <!--
                Named because signing out lands here with the keyboard needing somewhere to go: the vault's
                controls have just been collapsed, and Focus() on a collapsed control is a no-op that is
                not replayed. See MainWindow.axaml.cs.
              -->
              <TextBox x:Name="ServerUrlBox" Text="{Binding ServerUrl}"
                       PlaceholderText="https://dodossh.example" />
              <Button Classes="accent" Content="SIGN IN WITH YOUR BROWSER" Command="{Binding SignInCommand}"
                      IsEnabled="{Binding !IsBusy}" HorizontalAlignment="Left" />
              <TextBlock Classes="hint" Text="{Binding StatusMessage}" />
            </StackPanel>
          </Border>

          <Border Classes="card" IsVisible="{Binding IsNeedingEnrollment}">
            <StackPanel Spacing="12">
              <TextBlock Classes="heading" Text="Choose a keychain passphrase" />
              <TextBlock Classes="hint"
                         Text="This passphrase never leaves this machine, and the server cannot reset it. It is the only thing standing between a stolen copy of the database and every credential in your keychain." />
              <TextBox Text="{Binding Passphrase}" PlaceholderText="passphrase" PasswordChar="•" />
              <TextBox Text="{Binding ConfirmPassphrase}" PlaceholderText="again" PasswordChar="•" />
              <Button Classes="accent" Content="CREATE MY KEYCHAIN" Command="{Binding EnrollCommand}"
                      IsEnabled="{Binding !IsBusy}" HorizontalAlignment="Left" />
              <TextBlock Classes="hint" Text="{Binding StatusMessage}" />
            </StackPanel>
          </Border>

          <!--
            Shown once and impossible to skip. This is the only moment the code exists, and losing it
            together with the passphrase means the keychain is unrecoverable — there is no server-side reset
            by design.
          -->
          <Border Classes="card" IsVisible="{Binding IsShowingRecoveryCode}">
            <StackPanel Spacing="12">
              <TextBlock Classes="heading" Text="Write this recovery code down" />
              <TextBlock Classes="hint"
                         Text="It is shown once and is not stored anywhere. Without it, forgetting your passphrase means losing the keychain: nobody — including whoever runs the server — can recover it for you." />
              <Border Background="{StaticResource Raised}" BorderBrush="{StaticResource Border}"
                      BorderThickness="1" CornerRadius="6" Padding="14">
                <SelectableTextBlock Classes="mono" Text="{Binding RecoveryCode}"
                                     FontSize="17" Foreground="{StaticResource Accent}"
                                     TextWrapping="Wrap" />
              </Border>
              <CheckBox IsChecked="{Binding RecoveryCodeWrittenDown}"
                        Content="I have written it down somewhere safe" />
              <Button Classes="accent" Content="CONTINUE" Command="{Binding ConfirmRecoveryCodeCommand}"
                      HorizontalAlignment="Left" />
              <TextBlock Classes="hint" Text="{Binding StatusMessage}" />
            </StackPanel>
          </Border>

          <!--
            The unlock card, and the sign-out confirmation that replaces it. Both live in their own files:
            nothing inside this window can be laid out by a test — WebView2's adapter refuses the headless
            session's thread — so markup that stays here is markup nobody can measure. See UnlockCard.axaml.
          -->
          <Border Classes="card" IsVisible="{Binding IsAskingForThePassphrase}">
            <views:UnlockCard x:Name="UnlockPane" />
          </Border>

          <!--
            The confirmation, in place of the unlock card rather than under it: the card is already close
            to the height the window guarantees at its minimum, and a screen a user cannot read all of is
            worse than one that shows one question at a time.
          -->
          <Border Classes="card" IsVisible="{Binding IsConfirmingSignOut}">
            <views:SignOutCard />
          </Border>

        </Panel>
      </Border>

      <!--
        Last, so it is over everything Avalonia draws. It is over the terminal too, because opening it
        collapses the terminal — see IsTerminalShowing.
      -->
      <views:QuickConnect x:Name="Palette" IsVisible="{Binding IsSearching}" />

    </Panel>

    <views:StatusBar Grid.Row="2" />

  </Grid>

</Window>
