Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Globalization
Imports System.Reflection
Imports Nexamas.UI.Controls

Namespace Nexamas.UI.Application

    ''' <summary>
    ''' Read-only structural proof that Application owns direct control admission, retained layout-session
    ''' replacement, and framework-internal geometry mutation through one controls facade path.
    ''' </summary>
    ''' <remarks>
    ''' This audit deliberately uses reflection over already-compiled Nexamas UI types. It does not scan source files,
    ''' run captures, create controls, open windows, allocate bitmaps, mutate layout state, or introduce a second
    ''' ownership registry. Its only job is to keep Phase 0/1 closure facts executable inside the existing
    ''' Certification/Quality graph.
    ''' </remarks>
    Friend NotInheritable Class MASApplicationOwnershipClosureAudit
        Private Sub New()
        End Sub

        Friend Shared Function VerifyCurrent() As MASApplicationOwnershipClosureReport
            Dim findings As New List(Of MASApplicationOwnershipClosureFinding)()
            Dim controlsType As Type = GetType(MASApplicationWindowControls)
            Dim controlBaseType As Type = GetType(MASControlBase)

            RequireType(findings, controlsType, "MASApplicationWindowControls", "The Application controls facade type must be available for ownership closure.")
            RequireType(findings, controlBaseType, "MASControlBase", "The shared control base type must be available for geometry ownership closure.")

            If controlsType IsNot Nothing Then
                RequirePublicInstanceMethod(findings, controlsType, "Add", "Direct control admission remains a public Application facade route.")
                RequirePublicInstanceMethod(findings, controlsType, "AddControl", "Typed direct control admission remains a public Application facade route.")
                RequirePublicInstanceMethod(findings, controlsType, "Remove", "Direct removal must pass through the Application facade so retained layout can be released consistently.")
                RequirePublicInstanceMethod(findings, controlsType, "Clear", "Direct clear must pass through the Application facade so retained layout can be released consistently.")
                RequirePublicInstanceMethod(findings, controlsType, "PerformUpdate", "External direct mutation batching must stay centralized on the Application controls facade.")

                RequireNonPublicInstanceMethod(findings, controlsType, "AdoptConsumerOwnedControlInternal", "Direct Add must convert retained-layout ownership through one internal adoption gate.")
                RequireNonPublicInstanceMethod(findings, controlsType, "ReleaseRetainedLayoutForDirectMutationInternal", "Direct Remove/Clear/Place must release retained layout through one internal gate.")
                RequireNonPublicInstanceMethod(findings, controlsType, "ClearRetainedLayoutSessionsInternal", "Retained layout sessions must have one internal cleanup gate.")
                RequireNonPublicInstanceMethod(findings, controlsType, "ReconcileLayoutHostedControlsInternal", "Retained Application layout must reconcile hosted controls through one internal gate.")
                RequireNonPublicInstanceMethod(findings, controlsType, "TryApplySizeLayoutPlanInternal", "Application layout recipes must apply MASLayout plans through the diagnostic owner gate.")
                RequirePrivateInstanceMethod(findings, controlsType, "ApplySizeLayoutPlanCore", "The raw MASLayout plan applier must remain private so no alternate caller can bypass diagnostics.")

                RequireNoPublicInstanceMethod(findings, controlsType, "Place", "Direct placement is an advanced internal Application facade route and must not become a public geometry bypass.")

                RequirePrivateInstanceField(findings, controlsType, "_layoutPageSession", "LayoutPage retained session state must remain private to the Application controls facade.")
                RequirePrivateInstanceField(findings, controlsType, "_layoutRegionsSession", "LayoutRegions retained session state must remain private to the Application controls facade.")
                RequirePrivateInstanceField(findings, controlsType, "_layoutApplicationSurfaceSession", "LayoutApplicationSurface retained session state must remain private to the Application controls facade.")
                RequirePrivateInstanceField(findings, controlsType, "_layoutHostedControls", "Layout-hosted controls must be tracked in one private ownership set.")
                RequirePrivateInstanceField(findings, controlsType, "_retainedLayoutBuildAdmissionDepth", "Retained layout build admission must be scoped by one private depth counter.")
            End If

            If controlBaseType IsNot Nothing Then
                RequireNonPublicSetter(findings, controlBaseType, "BoundsLogical", "Control geometry must not expose a public raw BoundsLogical setter.")
                RequireNonPublicInstanceMethod(findings, controlBaseType, "SetLayoutPlacementInternal", "Framework layout placement must remain an internal mutation route.")
                RequireNonPublicInstanceMethod(findings, controlBaseType, "SetLocalLayoutBoundsInternal", "Local/composite child placement must remain framework-internal instead of public API.")
                RequireNonPublicInstanceMethod(findings, controlBaseType, "CreateLayoutSlotForBoundsInternal", "Fallback/direct bounds must still produce a MASLayoutSlot through the shared Size/Layout integration context.")
                RequireNonPublicInstanceMethod(findings, controlBaseType, "GetLayoutContentBoundsLogicalInternal", "Composite controls must have an internal slot-owned content-bounds gateway.")
            End If

            If findings.Count = 0 Then
                findings.Add(MASApplicationOwnershipClosureFinding.Info(
                    "MASApplicationOwnership.Closed",
                    "Application ownership closure is structurally closed: public admission is centralized, raw layout application is private, retained sessions are private, and control geometry setters remain non-public."))
            End If

            Return New MASApplicationOwnershipClosureReport(findings)
        End Function

        Private Shared Sub RequireType(findings As IList(Of MASApplicationOwnershipClosureFinding),
                                       candidateType As Type,
                                       key As String,
                                       summary As String)
            If candidateType Is Nothing Then
                findings.Add(MASApplicationOwnershipClosureFinding.[Error]("MASApplicationOwnership.MissingType." & key, summary))
            End If
        End Sub

        Private Shared Sub RequirePublicInstanceMethod(findings As IList(Of MASApplicationOwnershipClosureFinding),
                                                       ownerType As Type,
                                                       methodName As String,
                                                       summary As String)
            If Not HasMethod(ownerType, methodName, requirePublic:=True, requirePrivate:=False) Then
                findings.Add(MASApplicationOwnershipClosureFinding.[Error]("MASApplicationOwnership.MissingPublicMethod." & methodName, summary))
            End If
        End Sub

        Private Shared Sub RequireNonPublicInstanceMethod(findings As IList(Of MASApplicationOwnershipClosureFinding),
                                                          ownerType As Type,
                                                          methodName As String,
                                                          summary As String)
            If Not HasMethod(ownerType, methodName, requirePublic:=False, requirePrivate:=False) Then
                findings.Add(MASApplicationOwnershipClosureFinding.[Error]("MASApplicationOwnership.MissingInternalMethod." & methodName, summary))
            End If
        End Sub

        Private Shared Sub RequirePrivateInstanceMethod(findings As IList(Of MASApplicationOwnershipClosureFinding),
                                                        ownerType As Type,
                                                        methodName As String,
                                                        summary As String)
            If Not HasMethod(ownerType, methodName, requirePublic:=False, requirePrivate:=True) Then
                findings.Add(MASApplicationOwnershipClosureFinding.[Error]("MASApplicationOwnership.MissingPrivateMethod." & methodName, summary))
            End If
        End Sub

        Private Shared Sub RequireNoPublicInstanceMethod(findings As IList(Of MASApplicationOwnershipClosureFinding),
                                                         ownerType As Type,
                                                         methodName As String,
                                                         summary As String)
            If HasMethod(ownerType, methodName, requirePublic:=True, requirePrivate:=False) Then
                findings.Add(MASApplicationOwnershipClosureFinding.[Error]("MASApplicationOwnership.PublicGeometryBypass." & methodName, summary))
            End If
        End Sub

        Private Shared Sub RequirePrivateInstanceField(findings As IList(Of MASApplicationOwnershipClosureFinding),
                                                       ownerType As Type,
                                                       fieldName As String,
                                                       summary As String)
            Dim field As FieldInfo = ownerType.GetField(fieldName, BindingFlags.Instance Or BindingFlags.NonPublic)
            If field Is Nothing OrElse Not field.IsPrivate Then
                findings.Add(MASApplicationOwnershipClosureFinding.[Error]("MASApplicationOwnership.MissingPrivateField." & fieldName, summary))
            End If
        End Sub

        Private Shared Sub RequireNonPublicSetter(findings As IList(Of MASApplicationOwnershipClosureFinding),
                                                  ownerType As Type,
                                                  propertyName As String,
                                                  summary As String)
            Dim prop As PropertyInfo = ownerType.GetProperty(propertyName, BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.NonPublic)
            If prop Is Nothing Then
                findings.Add(MASApplicationOwnershipClosureFinding.[Error]("MASApplicationOwnership.MissingProperty." & propertyName, summary))
                Return
            End If

            Dim setter As MethodInfo = prop.GetSetMethod(nonPublic:=True)
            If setter Is Nothing OrElse setter.IsPublic Then
                findings.Add(MASApplicationOwnershipClosureFinding.[Error]("MASApplicationOwnership.PublicSetter." & propertyName, summary))
            End If
        End Sub

        Private Shared Function HasMethod(ownerType As Type,
                                          methodName As String,
                                          requirePublic As Boolean,
                                          requirePrivate As Boolean) As Boolean
            If ownerType Is Nothing OrElse String.IsNullOrWhiteSpace(methodName) Then Return False

            Dim methods As MethodInfo() = ownerType.GetMethods(BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.NonPublic)
            For Each method As MethodInfo In methods
                If method Is Nothing Then Continue For
                If Not String.Equals(method.Name, methodName, StringComparison.Ordinal) Then Continue For
                If requirePublic AndAlso Not method.IsPublic Then Continue For
                If Not requirePublic AndAlso method.IsPublic Then Continue For
                If requirePrivate AndAlso Not method.IsPrivate Then Continue For
                Return True
            Next

            Return False
        End Function
    End Class

    Friend NotInheritable Class MASApplicationOwnershipClosureReport
        Private ReadOnly _findings As IReadOnlyList(Of MASApplicationOwnershipClosureFinding)

        Friend Sub New(findings As IEnumerable(Of MASApplicationOwnershipClosureFinding))
            Dim normalized As New List(Of MASApplicationOwnershipClosureFinding)()
            If findings IsNot Nothing Then
                For Each finding As MASApplicationOwnershipClosureFinding In findings
                    If finding IsNot Nothing Then normalized.Add(finding)
                Next
            End If

            _findings = New ReadOnlyCollection(Of MASApplicationOwnershipClosureFinding)(normalized)
        End Sub

        Friend ReadOnly Property Findings As IReadOnlyList(Of MASApplicationOwnershipClosureFinding)
            Get
                Return _findings
            End Get
        End Property

        Friend ReadOnly Property FindingCount As Integer
            Get
                Return Findings.Count
            End Get
        End Property

        Friend ReadOnly Property ErrorCount As Integer
            Get
                Return CountBySeverity(MASApplicationOwnershipClosureFindingSeverity.Error)
            End Get
        End Property

        Friend ReadOnly Property WarningCount As Integer
            Get
                Return CountBySeverity(MASApplicationOwnershipClosureFindingSeverity.Warning)
            End Get
        End Property

        Friend ReadOnly Property IsClosed As Boolean
            Get
                Return ErrorCount = 0
            End Get
        End Property

        Friend ReadOnly Property Summary As String
            Get
                Return "Application ownership closure: " &
                       ErrorCount.ToString(CultureInfo.InvariantCulture) & " error(s), " &
                       WarningCount.ToString(CultureInfo.InvariantCulture) & " warning(s), " &
                       FindingCount.ToString(CultureInfo.InvariantCulture) & " finding(s)."
            End Get
        End Property

        Friend Function CreateFindingDetails(maxCount As Integer) As IReadOnlyList(Of String)
            Dim details As New List(Of String)()
            Dim limit As Integer = Math.Max(1, maxCount)

            For Each finding As MASApplicationOwnershipClosureFinding In Findings
                If finding Is Nothing Then Continue For
                details.Add(finding.ToString())
                If details.Count >= limit Then Exit For
            Next

            Return New ReadOnlyCollection(Of String)(details)
        End Function

        Friend Function CreateSummaryDetails() As IReadOnlyList(Of String)
            Return New ReadOnlyCollection(Of String)(New List(Of String) From {
                Summary,
                "Application control admission route: MASApplicationWindowControls.Add/AddControl.",
                "Application layout placement route: MASApplicationWindowControls.TryApplySizeLayoutPlanInternal -> private ApplySizeLayoutPlanCore.",
                "Control geometry route: MASControlBase.SetLayoutPlacementInternal / SetLocalLayoutBoundsInternal remain non-public."
            })
        End Function

        Private Function CountBySeverity(severity As MASApplicationOwnershipClosureFindingSeverity) As Integer
            Dim count As Integer = 0
            For Each finding As MASApplicationOwnershipClosureFinding In Findings
                If finding IsNot Nothing AndAlso finding.Severity = severity Then count += 1
            Next
            Return count
        End Function
    End Class

    Friend NotInheritable Class MASApplicationOwnershipClosureFinding
        Private Sub New(key As String,
                        severity As MASApplicationOwnershipClosureFindingSeverity,
                        summary As String)
            Me.Key = NormalizeText(key)
            Me.Severity = severity
            Me.Summary = NormalizeText(summary)
        End Sub

        Friend ReadOnly Property Key As String
        Friend ReadOnly Property Severity As MASApplicationOwnershipClosureFindingSeverity
        Friend ReadOnly Property Summary As String

        Friend Shared Function Info(key As String, summary As String) As MASApplicationOwnershipClosureFinding
            Return New MASApplicationOwnershipClosureFinding(key, MASApplicationOwnershipClosureFindingSeverity.Info, summary)
        End Function

        Friend Shared Function Warning(key As String, summary As String) As MASApplicationOwnershipClosureFinding
            Return New MASApplicationOwnershipClosureFinding(key, MASApplicationOwnershipClosureFindingSeverity.Warning, summary)
        End Function

        Friend Shared Function [Error](key As String, summary As String) As MASApplicationOwnershipClosureFinding
            Return New MASApplicationOwnershipClosureFinding(key, MASApplicationOwnershipClosureFindingSeverity.Error, summary)
        End Function

        Public Overrides Function ToString() As String
            Return Severity.ToString() & " | " & Key & " | " & Summary
        End Function

        Private Shared Function NormalizeText(value As String) As String
            Return If(value, String.Empty).Trim()
        End Function
    End Class

    Friend Enum MASApplicationOwnershipClosureFindingSeverity
        Info = 0
        Warning = 1
        [Error] = 2
    End Enum

End Namespace
