﻿Option Strict On
Option Explicit On

Imports System
Imports System.Globalization
Imports System.Windows.Forms
Imports Nexamas.UI.Application
Imports Nexamas.UI.Components
Imports Nexamas.UI.Controls
Imports Nexamas.UI.Icons
Imports Nexamas.UI.Layout
Imports SkiaSharp

Partial Friend NotInheritable Class ShowcasePageHostContentBuilder

    Private NotInheritable Class ShowcaseIconResolver
        Implements IMASIconResolver

        Private ReadOnly _syncRoot As New Object()
        Private _lastRequestSummary As String = "No icon request has been observed yet. The controls will request icons when their rows/nodes are measured and painted."

        Friend ReadOnly Property LastRequestSummary As String
            Get
                SyncLock _syncRoot
                    Return _lastRequestSummary
                End SyncLock
            End Get
        End Property

        Public Function ResolveIcon(request As MASIconRequest) As MASIconResult Implements IMASIconResolver.ResolveIcon
            If request Is Nothing Then Return MASIconResult.None()

            Dim summary As String = String.Format(
                CultureInfo.InvariantCulture,
                "DisplayName='{0}' | Kind={1} | Extension='{2}' | Size={3:0.#} DIP | DPI={4:0.###} | SizePx={5}",
                request.DisplayName,
                request.Kind,
                request.Extension,
                request.SizeDip,
                request.Dpi,
                request.SizePx)
            SyncLock _syncRoot
                _lastRequestSummary = summary
            End SyncLock

            If request.Kind = MASIconObjectKind.Folder Then Return MASIconResult.FromMasIcon(MASIconKind.Folder)
            If request.Kind = MASIconObjectKind.Drive Then Return MASIconResult.FromMasIcon(MASIconKind.Drive)

            Select Case request.Extension
                Case ".vb", ".cs", ".json"
                    Return MASIconResult.FromMasIcon(MASIconKind.Edit)
                Case ".zip", ".nupkg"
                    Return MASIconResult.FromMasIcon(MASIconKind.Export)
                Case ".png", ".jpg", ".jpeg"
                    Return MASIconResult.FromMasIcon(MASIconKind.GridView)
                Case ".md", ".txt"
                    Return MASIconResult.FromMasIcon(MASIconKind.Info)
                Case Else
                    Return MASIconResult.FromMasIcon(MASIconKind.File)
            End Select
        End Function
    End Class

    Private NotInheritable Class ShowcaseSecondaryWindowLifetime
        Implements IDisposable

        Private _owner As Form
        Private _window As MASApplicationWindow
        Private _disposed As Boolean

        Friend Sub New(owner As Form, window As MASApplicationWindow)
            _owner = owner
            _window = window
        End Sub

        Public Sub Dispose() Implements IDisposable.Dispose
            If _disposed Then Return
            _disposed = True

            Try
                If _window IsNot Nothing AndAlso Not _window.IsDisposed Then _window.Dispose()
            Finally
                If _owner IsNot Nothing AndAlso Not _owner.IsDisposed Then
                    If _owner.Visible Then _owner.Close()
                    _owner.Dispose()
                End If
                _window = Nothing
                _owner = Nothing
            End Try
        End Sub
    End Class

    Private Shared Sub BuildIconResolution(page As MASApplicationLayoutPageBuilder,
                                           window As MASApplicationWindow)
        AddShowcaseContent(page, Body(window, "This live page supplies one external IMASIconResolver to both MASListView and MASTreeView. Nexamas.UI creates MASIconRequest instances, the resolver reads public request metadata, and returns MASIconResult without owning the controls or drawing icons itself."), MASSize.FillWidth)

        Dim resolver As New ShowcaseIconResolver()
        Dim requestStatus As MASLabel = Body(window, resolver.LastRequestSummary)

        Dim listView As MASListView = window.Controls.AddListView(configure:=Sub(view As MASListView)
                                                                      view.WithDetailsView().StandaloneChrome()
                                                                      view.AddColumn("Object", 210.0F)
                                                                      view.AddColumn("Resolver decision", 280.0F)
                                                                      view.Add(MASListViewItem.Create("Documentation").AsFolder().WithSubItems(New String() {"Folder icon"}))
                                                                      view.Add(MASListViewItem.Create("README.md").AsFile().WithSubItems(New String() {"Info icon from .md"}))
                                                                      view.Add(MASListViewItem.Create("Nexamas.UI.vb").AsFile().WithSubItems(New String() {"Edit icon from .vb"}))
                                                                      view.Add(MASListViewItem.Create("Nexamas.UI.1.0.0.nupkg").AsFile().WithSubItems(New String() {"Export icon from .nupkg"}))
                                                                  End Sub)
        listView.WithIconResolver(resolver, ownsResolver:=False)
        listView.WithSize(MASSize.FillWidth.OffsetHeight(220.0F))

        Dim treeView As MASTreeView = window.Controls.AddTreeView(configure:=Sub(tree As MASTreeView)
                                                                      Dim rootNode As MASTreeNode = tree.AddRoot("Nexamas.UI")
                                                                      rootNode.AddChild("Controls")
                                                                      rootNode.AddChild("Icons")
                                                                      rootNode.AddChild("Quality proof")
                                                                      tree.SelectedNode = rootNode
                                                                  End Sub)
        treeView.WithIconResolver(resolver, ownsResolver:=False).WithNodeIcons(True)
        treeView.WithSize(MASSize.FillWidth.OffsetHeight(220.0F))

        Dim refresh As MASButton = window.Controls.AddButton("Read latest resolver request").AsPrimary()
        AddHandler refresh.Click,
            Sub(sender As Object, e As EventArgs)
                requestStatus.Text = resolver.LastRequestSummary
                window.Refresh()
            End Sub

        page.Grid(2).Gap(MASLayoutSpacing.Large).EqualItemSize().Add(listView, MASSize.FillWidth).Add(treeView, MASSize.FillWidth)
        AddShowcaseContent(page, Heading(window, "Latest public MASIconRequest"), MASSize.HugContent)
        AddShowcaseContent(page, requestStatus, MASSize.FillWidth)
        AddNaturalActionGroup(page, refresh)
        AddShowcaseContent(page, Muted(window, "Ownership decision: ownsResolver:=False is explicit because the same stateless resolver instance is shared by two controls. The Showcase does not construct MASIconRequest, cache images, or invoke internal icon painters."), MASSize.FillWidth)
    End Sub

    Private Shared Sub BuildApplicationLifetime(page As MASApplicationLayoutPageBuilder,
                                                window As MASApplicationWindow,
                                                application As MASApplication,
                                                registerLifetime As Action(Of IDisposable))
        AddShowcaseContent(page, Body(window, "This page proves the documented multi-window route using the already-owned MASApplication. It creates a real secondary Form owner, then calls MASApplication.CreateWindow(owner), and registers cleanup with the Showcase page lifetime so navigation cannot orphan the window."), MASSize.FillWidth)

        If application Is Nothing Then
            AddShowcaseContent(page, window.Controls.AddStatusBanner("Application facade unavailable", "The Showcase will not invent a second MASApplication. This route requires the shell-owned ApplicationFacade.", MASToastTone.Danger), MASSize.FillWidth)
            Return
        End If

        Dim status As MASLabel = Body(window, "Current MASApplication.WindowCount = " & application.WindowCount.ToString(CultureInfo.InvariantCulture))
        Dim openWindow As MASButton = window.Controls.AddButton("Open secondary Nexamas.UI window").AsPrimary()
        Dim refreshCount As MASButton = window.Controls.AddButton("Refresh WindowCount")

        AddHandler refreshCount.Click,
            Sub(sender As Object, e As EventArgs)
                status.Text = "Current MASApplication.WindowCount = " & application.WindowCount.ToString(CultureInfo.InvariantCulture)
                window.Refresh()
            End Sub

        AddHandler openWindow.Click,
            Sub(sender As Object, e As EventArgs)
                Try
                    OpenSecondaryWindowForLifetimeProof(application, registerLifetime)
                    status.Text = "Secondary window opened. MASApplication.WindowCount = " & application.WindowCount.ToString(CultureInfo.InvariantCulture)
                    window.Refresh()
                Catch ex As Exception
                    window.Services.Dialogs.Error("Secondary window could not be created: " & ex.Message, "Multi-window lifetime")
                End Try
            End Sub

        AddShowcaseContent(page, status, MASSize.FillWidth)
        AddNaturalActionGroup(page, openWindow, refreshCount)

        Dim matrix As MASDataGrid = window.Controls.AddDataGrid()
        matrix.AddColumn("Step", "Step")
        matrix.AddColumn("Public API", "Public API")
        matrix.AddColumn("Ownership proof", "Ownership proof")
        matrix.AddRow("Create", "MASApplication.CreateWindow(owner)", "Uses the shell-owned application; no second application is invented.")
        matrix.AddRow("Inspect", "MASApplication.WindowCount", "Shows active windows owned by the application facade.")
        matrix.AddRow("Owner close", "FormClosed / Dispose", "The Form owner and MASApplicationWindow close together.")
        matrix.AddRow("Route cleanup", "RegisterPageLifetime", "Leaving the route disposes any secondary proof window.")
        FitDataGridToRows(matrix)
        AddShowcaseContent(page, matrix, MASSize.FillWidth)
    End Sub

    Friend Shared Function OpenSecondaryWindowForLifetimeProof(application As MASApplication,
                                                                  registerLifetime As Action(Of IDisposable)) As IDisposable
        If application Is Nothing Then Throw New ArgumentNullException(NameOf(application))

        Dim childForm As New Form() With {
            .Text = "Nexamas.UI secondary lifetime proof",
            .ClientSize = New System.Drawing.Size(860, 560),
            .MinimumSize = New System.Drawing.Size(720, 480),
            .StartPosition = FormStartPosition.CenterParent,
            .AutoScaleMode = AutoScaleMode.Dpi,
            .FormBorderStyle = FormBorderStyle.None,
            .BackColor = System.Drawing.Color.White,
            .KeyPreview = True
        }
        Dim childWindow As MASApplicationWindow = Nothing

        Try
            ' This is the single implementation used by both the live page button and
            ' the automated lifetime smoke. It remains a public-consumer sequence.
            childWindow = application.CreateWindow(
                owner:=childForm,
                dockStyle:=DockStyle.Fill,
                setupImmediately:=False)
            childWindow.Chrome.UseSoftShadow(MASWindowShadowMode.PopupSafe)
            childWindow.Shell.AttachStandardTopBar(
                title:=childForm.Text,
                showLogo:=False,
                attachWindow:=True)
            childWindow.Setup()

            Dim closeButton As MASButton = childWindow.Controls.AddButton("Close secondary window").AsPrimary()
            AddHandler closeButton.Click, Sub() childForm.Close()

            Dim description As MASLabel = childWindow.Controls.AddLabel(
                "This window shares the same MASApplication. Closing its owner removes it from WindowCount and disposes its MASApplicationWindow lifetime.")
            description.MultiLine = True
            description.WordWrap = True
            description.WithSize(MASSize.FillWidth)

            childWindow.Controls.LayoutPage(
                Sub(childPage As MASApplicationLayoutPageBuilder)
                    childPage.Padding(MASLayoutSpacing.Spacious).Spacing(MASLayoutSpacing.Medium)
                    childPage.FullWidth(childWindow.Controls.AddTitle("Secondary Nexamas.UI window"), MASSize.FillWidth)
                    childPage.FullWidth(description, MASSize.FillWidth)
                    childPage.ActionGroup(Sub(actions As MASApplicationActionGroupLayoutBuilder)
                                              actions.AlignCenter().Add(closeButton, MASSize.HugContent)
                                          End Sub)
                End Sub)

            Dim lifetime As New ShowcaseSecondaryWindowLifetime(childForm, childWindow)
            If registerLifetime IsNot Nothing Then registerLifetime.Invoke(lifetime)
            childForm.Show()
            Return lifetime
        Catch
            If childWindow IsNot Nothing AndAlso Not childWindow.IsDisposed Then childWindow.Dispose()
            If Not childForm.IsDisposed Then childForm.Dispose()
            Throw
        End Try
    End Function

    Private Shared Sub BuildDpiTextAccessibility(page As MASApplicationLayoutPageBuilder,
                                                 window As MASApplicationWindow)
        AddShowcaseContent(page, Body(window, "This evidence page reads the public MASApplicationWindow.Geometry facade, displays multilingual text, and provides a keyboard-focusable input. It does not claim a public Screen Reader or UI Automation integration because no such consumer facade exists in the pinned V1 API."), MASSize.FillWidth)

        Dim boundary As MASStatusBanner = window.Controls.AddStatusBanner(
            "Accessibility claim boundary",
            "DPI geometry, text rendering, keyboard focus, and virtualization range evidence are testable here. Screen Reader / UI Automation is explicitly Not claimed until Nexamas.UI exposes and documents a public automation contract.",
            MASToastTone.Warning)
        AddShowcaseContent(page, boundary, MASSize.FillWidth)

        Dim multilingual As MASLabel = window.Controls.AddLabel("English · Deutsch · العربية · עברית · हिन्दी · 日本語 — 125% / 150% DPI text wrapping proof")
        multilingual.MultiLine = True
        multilingual.WordWrap = True
        multilingual.WithSize(MASSize.FillWidth)
        Dim focusInput As MASTextBox = window.Controls.AddTextBox("Use Tab / Shift+Tab and edit this multilingual text: مرحباً Nexamas.UI")
        focusInput.WithSize(MASSize.FillWidth)
        Dim geometryStatus As MASLabel = Body(window, "Select Refresh geometry evidence after resizing or moving the window between DPI-scaled displays.")
        Dim refresh As MASButton = window.Controls.AddButton("Refresh geometry evidence").AsPrimary()

        Dim matrix As MASDataGrid = window.Controls.AddDataGrid()
        matrix.AddColumn("Evidence", "Evidence")
        matrix.AddColumn("Public route", "Public route")
        matrix.AddColumn("Current result / claim", "Current result / claim")

        Dim refreshEvidence As Action(Of Boolean) =
            Sub(requestWindowRefresh As Boolean)
                matrix.DataView.ClearRows()
                Dim logicalSample As New SKRect(0.0F, 0.0F, 320.0F, 96.0F)
                Dim pixelSample As SKRect = window.Geometry.LogicalToPx(logicalSample)
                Dim roundTrip As SKRect = window.Geometry.PxToLogical(pixelSample)
                Dim logicalBounds As SKRect = window.Geometry.ControlOuterBoundsLogical(multilingual)
                Dim pixelBounds As SKRect = window.Geometry.ControlOuterBoundsPx(multilingual)
                matrix.AddRow("DPI", "MASApplicationWindow.Geometry.Dpi", window.Geometry.Dpi.ToString("0.###", CultureInfo.InvariantCulture))
                matrix.AddRow("Surface pixels", "Geometry.SurfaceSizePx", window.Geometry.SurfaceSizePx.Width.ToString(CultureInfo.InvariantCulture) & " × " & window.Geometry.SurfaceSizePx.Height.ToString(CultureInfo.InvariantCulture))
                matrix.AddRow("DIP → PX", "Geometry.LogicalToPx", FormatGeometryRect(pixelSample))
                matrix.AddRow("PX → DIP", "Geometry.PxToLogical", FormatGeometryRect(roundTrip))
                matrix.AddRow("Control bounds DIP", "ControlOuterBoundsLogical", FormatGeometryRect(logicalBounds))
                matrix.AddRow("Control bounds PX", "ControlOuterBoundsPx", FormatGeometryRect(pixelBounds))
                matrix.AddRow("Multilingual text", "MASLabel", "Live wrapping sample rendered by Nexamas.UI")
                matrix.AddRow("Keyboard / focus", "MASTextBox", "Interactive runtime evidence; verify Tab and Shift+Tab")
                matrix.AddRow("Screen Reader / UI Automation", "No pinned public facade", "Not claimed")
                FitDataGridToRows(matrix, maximumVisibleRows:=10)
                geometryStatus.Text = "Geometry refreshed at DPI scale " & window.Geometry.Dpi.ToString("0.###", CultureInfo.InvariantCulture) & ". Resize and repeat at 100%, 125%, and 150%."
                If requestWindowRefresh Then window.Refresh()
            End Sub
        AddHandler refresh.Click, Sub(sender As Object, e As EventArgs) refreshEvidence.Invoke(True)

        AddShowcaseContent(page, multilingual, MASSize.FillWidth)
        AddShowcaseContent(page, focusInput, MASSize.FillWidth)
        AddShowcaseContent(page, geometryStatus, MASSize.FillWidth)
        AddNaturalActionGroup(page, refresh)
        refreshEvidence.Invoke(False)
        AddShowcaseContent(page, matrix, MASSize.FillWidth)
    End Sub

    Private Shared Function FormatGeometryRect(value As SKRect) As String
        Return String.Format(CultureInfo.InvariantCulture, "L={0:0.##}, T={1:0.##}, R={2:0.##}, B={3:0.##}", value.Left, value.Top, value.Right, value.Bottom)
    End Function

End Class
