Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Reflection
Imports Nexamas.UI.Rendering
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Components

    ''' <summary>
    ''' Phase-3 contract gate for ImageViewer surface architecture. The gate verifies that the
    ''' ImageViewer no longer relies on one broad root material for all chrome, that every visual
    ''' region resolves through the official Surface Material profile/composition path, and that
    ''' legacy media painter routes are absent from the compiled assembly.
    ''' </summary>
    Friend NotInheritable Class MASImageViewerSurfaceContractAudit
        Private Sub New()
        End Sub

        Friend Shared Function BuildCurrentSurfaceContract() As MASImageViewerSurfaceContractReport
            Dim hasSurfacePolicy As Boolean = GetType(MASImageViewerSurfacePolicy).IsNotPublic
            Dim hasMediaSurfaceProfile As Boolean = MASSurfaceMaterialSlotProfileRegistry.Resolve(MASImageViewerSurfacePolicy.DefaultProfileId) IsNot Nothing
            Dim composition As MASComponentSurfaceMaterialComposition = MASImageViewerSurfacePolicy.CreateComposition()

            Dim rootKey As String = ResolveMaterialKey(composition, MASComponentSurfaceRegion.Root)
            Dim toolbarKey As String = ResolveMaterialKey(composition, MASComponentSurfaceRegion.Toolbar)
            Dim viewportKey As String = ResolveMaterialKey(composition, MASComponentSurfaceRegion.Viewport)
            Dim footerKey As String = ResolveMaterialKey(composition, MASComponentSurfaceRegion.Footer)
            Dim overlayKey As String = ResolveMaterialKey(composition, MASComponentSurfaceRegion.Overlay)

            Dim hasRegionBindings As Boolean = HasAuthoredBinding(composition, MASComponentSurfaceRegion.Root) AndAlso
                                                HasAuthoredBinding(composition, MASComponentSurfaceRegion.Toolbar) AndAlso
                                                HasAuthoredBinding(composition, MASComponentSurfaceRegion.Viewport) AndAlso
                                                HasAuthoredBinding(composition, MASComponentSurfaceRegion.Footer) AndAlso
                                                HasAuthoredBinding(composition, MASComponentSurfaceRegion.Overlay)
            Dim hasIndependentRegionMaterials As Boolean = HasIndependentMaterialDistribution(rootKey, toolbarKey, viewportKey, footerKey, overlayKey)
            Dim hasExpectedDefaultMaterialMap As Boolean = CheckExpectedDefaultMaterialMap(rootKey, toolbarKey, viewportKey, footerKey, overlayKey)
            Dim hasOfficialMaterials As Boolean = HasOfficialMaterial(rootKey) AndAlso
                                                  HasOfficialMaterial(toolbarKey) AndAlso
                                                  HasOfficialMaterial(viewportKey) AndAlso
                                                  HasOfficialMaterial(footerKey) AndAlso
                                                  HasOfficialMaterial(overlayKey)
            Dim hasPanelShellRootProof As Boolean = CheckPanelShellRootProof(rootKey)
            Dim hasLayoutRegionProof As Boolean = CheckLayoutRegionProof()
            Dim hasRenderRouteProof As Boolean = CheckRenderRouteProof()
            Dim hasNoLegacyMediaPainterPath As Boolean = CheckNoLegacyMediaPainterPath()
            Dim hasProfileSwitchProof As Boolean = CheckProfileSwitchProof(rootKey, toolbarKey, viewportKey, footerKey, overlayKey)
            Dim hasNoMediaShellLiteralInImageViewer As Boolean = CheckNoMediaShellLiteralInImageViewer()

            Dim status As MASImageViewerSurfaceContractStatus = DetermineStatus(
                hasSurfacePolicy,
                hasMediaSurfaceProfile,
                hasRegionBindings,
                hasIndependentRegionMaterials,
                hasExpectedDefaultMaterialMap,
                hasOfficialMaterials,
                hasPanelShellRootProof,
                hasLayoutRegionProof,
                hasRenderRouteProof,
                hasNoLegacyMediaPainterPath,
                hasProfileSwitchProof,
                hasNoMediaShellLiteralInImageViewer)

            Return New MASImageViewerSurfaceContractReport(
                name:="MASImageViewer Surface Contract",
                status:=status,
                hasSurfacePolicy:=hasSurfacePolicy,
                hasMediaSurfaceProfile:=hasMediaSurfaceProfile,
                hasRegionBindings:=hasRegionBindings,
                hasIndependentRegionMaterials:=hasIndependentRegionMaterials,
                hasExpectedDefaultMaterialMap:=hasExpectedDefaultMaterialMap,
                hasOfficialMaterials:=hasOfficialMaterials,
                hasPanelShellRootProof:=hasPanelShellRootProof,
                hasLayoutRegionProof:=hasLayoutRegionProof,
                hasRenderRouteProof:=hasRenderRouteProof,
                hasNoLegacyMediaPainterPath:=hasNoLegacyMediaPainterPath,
                hasProfileSwitchProof:=hasProfileSwitchProof,
                hasNoMediaShellLiteralInImageViewer:=hasNoMediaShellLiteralInImageViewer,
                rootMaterialKey:=rootKey,
                toolbarMaterialKey:=toolbarKey,
                viewportMaterialKey:=viewportKey,
                footerMaterialKey:=footerKey,
                overlayMaterialKey:=overlayKey,
                evidence:=Evidence(rootKey, toolbarKey, viewportKey, footerKey, overlayKey))
        End Function

        Private Shared Function DetermineStatus(hasSurfacePolicy As Boolean,
                                                hasMediaSurfaceProfile As Boolean,
                                                hasRegionBindings As Boolean,
                                                hasIndependentRegionMaterials As Boolean,
                                                hasExpectedDefaultMaterialMap As Boolean,
                                                hasOfficialMaterials As Boolean,
                                                hasPanelShellRootProof As Boolean,
                                                hasLayoutRegionProof As Boolean,
                                                hasRenderRouteProof As Boolean,
                                                hasNoLegacyMediaPainterPath As Boolean,
                                                hasProfileSwitchProof As Boolean,
                                                hasNoMediaShellLiteralInImageViewer As Boolean) As MASImageViewerSurfaceContractStatus
            If Not hasSurfacePolicy Then Return MASImageViewerSurfaceContractStatus.MissingSurfacePolicy
            If Not hasMediaSurfaceProfile Then Return MASImageViewerSurfaceContractStatus.MissingMediaSurfaceProfile
            If Not hasRegionBindings Then Return MASImageViewerSurfaceContractStatus.MissingRegionBindings
            If Not hasIndependentRegionMaterials Then Return MASImageViewerSurfaceContractStatus.MissingIndependentRegionMaterials
            If Not hasExpectedDefaultMaterialMap Then Return MASImageViewerSurfaceContractStatus.UnexpectedDefaultMaterialMap
            If Not hasOfficialMaterials Then Return MASImageViewerSurfaceContractStatus.MissingOfficialMaterials
            If Not hasPanelShellRootProof Then Return MASImageViewerSurfaceContractStatus.MissingPanelShellRootProof
            If Not hasLayoutRegionProof Then Return MASImageViewerSurfaceContractStatus.MissingLayoutRegionProof
            If Not hasRenderRouteProof Then Return MASImageViewerSurfaceContractStatus.MissingRenderRouteProof
            If Not hasNoLegacyMediaPainterPath Then Return MASImageViewerSurfaceContractStatus.LegacyMediaPainterPathPresent
            If Not hasProfileSwitchProof Then Return MASImageViewerSurfaceContractStatus.MissingProfileSwitchProof
            If Not hasNoMediaShellLiteralInImageViewer Then Return MASImageViewerSurfaceContractStatus.MediaShellLiteralPresent
            Return MASImageViewerSurfaceContractStatus.Closed
        End Function

        Private Shared Function ResolveMaterialKey(composition As MASComponentSurfaceMaterialComposition,
                                                   region As MASComponentSurfaceRegion) As String
            If composition Is Nothing Then Return String.Empty
            Dim binding As MASComponentSurfaceMaterialBinding = composition.Resolve(region, MASImageViewerSurfacePolicy.ResolveFallbackMaterialKey(region))
            If binding Is Nothing Then Return String.Empty
            Return Normalize(binding.MaterialKey)
        End Function

        Private Shared Function HasAuthoredBinding(composition As MASComponentSurfaceMaterialComposition,
                                                   region As MASComponentSurfaceRegion) As Boolean
            If composition Is Nothing Then Return False
            Dim binding As MASComponentSurfaceMaterialBinding = composition.Resolve(region, MASImageViewerSurfacePolicy.ResolveFallbackMaterialKey(region))
            Return binding IsNot Nothing AndAlso binding.IsAuthored AndAlso Normalize(binding.MaterialKey).Length > 0
        End Function

        Private Shared Function HasOfficialMaterial(materialKey As String) As Boolean
            Dim normalized As String = Normalize(materialKey)
            Return normalized.Length > 0 AndAlso MASSurfaceMaterialRegistry.Contains(normalized)
        End Function

        Private Shared Function HasIndependentMaterialDistribution(rootKey As String,
                                                                   toolbarKey As String,
                                                                   viewportKey As String,
                                                                   footerKey As String,
                                                                   overlayKey As String) As Boolean
            If Normalize(rootKey).Length = 0 OrElse Normalize(toolbarKey).Length = 0 OrElse Normalize(viewportKey).Length = 0 OrElse Normalize(footerKey).Length = 0 OrElse Normalize(overlayKey).Length = 0 Then Return False

            If Same(rootKey, toolbarKey) Then Return False
            If Same(rootKey, viewportKey) Then Return False
            If Same(rootKey, footerKey) Then Return False
            If Same(toolbarKey, viewportKey) AndAlso Not Same(viewportKey, MASSurfaceMaterialIds.MediaCommandRail) Then Return False
            If Same(footerKey, viewportKey) Then Return False

            Return True
        End Function

        Private Shared Function CheckExpectedDefaultMaterialMap(rootKey As String,
                                                              toolbarKey As String,
                                                              viewportKey As String,
                                                              footerKey As String,
                                                              overlayKey As String) As Boolean
            Return Same(rootKey, MASSurfaceMaterialIds.PlatformDefault) AndAlso
                   Same(toolbarKey, MASSurfaceMaterialIds.MediaCommandRail) AndAlso
                   Same(viewportKey, MASSurfaceMaterialIds.FrostedGlass) AndAlso
                   Same(footerKey, MASSurfaceMaterialIds.MediaFooterChrome) AndAlso
                   Same(overlayKey, MASSurfaceMaterialIds.MediaToolbarGlass)
        End Function

        Private Shared Function CheckPanelShellRootProof(rootMaterialKey As String) As Boolean
            If Not HasOfficialMaterial(rootMaterialKey) Then Return False

            Dim bounds As New SKRect(0.0F, 0.0F, 920.0F, 600.0F)
            Dim shellBounds As New SKRect(MediaContainerTokens.PanelShellHostInsetDip,
                                          MediaContainerTokens.PanelShellHostInsetDip,
                                          bounds.Right - MediaContainerTokens.PanelShellHostInsetDip,
                                          bounds.Bottom - MediaContainerTokens.PanelShellHostInsetDip)

            Dim spec As MASPanelShellSpec = MASPanelShellSpec.Create(shellBounds).
                WithoutHeader().
                WithDensity(MASPanelShellDensity.Normal).
                WithPadding(MediaContainerTokens.PanelShellContentPaddingDip).
                WithStrengths(
                    border:=MASPanelShellStrength.Level5,
                    surface:=MASPanelShellStrength.Level5).
                WithSurfaceMaterialKey(rootMaterialKey).
                Build()

            Dim result As MASPanelShellResult = MASPanelShellRenderer.Measure(1.0F, spec)
            If result Is Nothing Then Return False
            If result.HasHeader Then Return False
            If result.BaseRectPx.Width <= 1.0F OrElse result.BaseRectPx.Height <= 1.0F Then Return False
            If result.ContentRectPx.Width <= 1.0F OrElse result.ContentRectPx.Height <= 1.0F Then Return False
            If Math.Abs(result.BaseRectPx.Left - MediaContainerTokens.PanelShellHostInsetDip) > 0.51F Then Return False
            If Math.Abs(result.ContentRectPx.Left - (MediaContainerTokens.PanelShellHostInsetDip + MediaContainerTokens.PanelShellContentPaddingDip)) > 0.51F Then Return False
            Return result.RadiusPx > 0.0F
        End Function

        Private Shared Function CheckLayoutRegionProof() As Boolean
            Dim shellContent As New SKRect(24.0F, 24.0F, 896.0F, 576.0F)
            Dim plan As MASMediaContainerLayoutPlan = MASMediaContainerLayoutResolver.Resolve(
                bounds:=shellContent,
                dpi:=1.0F,
                toolbarChromeAllowed:=True,
                reserveToolbarChrome:=True,
                showFooter:=True,
                toolbarActionCount:=7)

            If plan.Surface.Width <= 1.0F OrElse plan.Surface.Height <= 1.0F Then Return False
            If plan.PreviewFrame.Width <= 1.0F OrElse plan.PreviewFrame.Height <= 1.0F Then Return False
            If plan.PreviewFrame.Left <= plan.Surface.Left + 0.51F Then Return False
            If plan.PreviewFrame.Bottom >= plan.Surface.Bottom - 0.51F Then Return False
            If plan.Toolbar.Width <= 1.0F OrElse plan.Toolbar.Height <= 1.0F Then Return False
            If plan.Stage.Width <= 1.0F OrElse plan.Stage.Height <= 1.0F Then Return False
            If plan.Viewport.Width <= 1.0F OrElse plan.Viewport.Height <= 1.0F Then Return False
            If plan.Footer.Width <= 1.0F OrElse plan.Footer.Height <= 1.0F Then Return False
            If plan.ToolbarFloating Then Return False
            If Math.Abs(plan.Toolbar.Top - plan.Surface.Top) > 0.51F Then Return False
            If plan.Toolbar.Bottom > plan.PreviewFrame.Top - 0.51F Then Return False
            If plan.Footer.Top < plan.Stage.Bottom - 0.51F Then Return False
            If plan.Footer.Bottom > plan.PreviewFrame.Bottom + 0.51F Then Return False
            If plan.Stage.Left < plan.PreviewFrame.Left - 0.51F OrElse plan.Stage.Right > plan.PreviewFrame.Right + 0.51F Then Return False
            If plan.Viewport.Top < plan.Stage.Top - 0.51F OrElse plan.Viewport.Bottom > plan.Stage.Bottom + 0.51F Then Return False
            Return True
        End Function

        Private Shared Function CheckRenderRouteProof() As Boolean
            Return HasCompositionParameterRoute("DrawPreviewFrameSurface") AndAlso
                   HasCompositionParameterRoute("DrawToolbar") AndAlso
                   HasCompositionParameterRoute("DrawFloatingToolbarSurface") AndAlso
                   HasCompositionParameterRoute("DrawFooter") AndAlso
                   HasCompositionParameterRoute("DrawFooterRailSurface") AndAlso
                   HasCompositionParameterRoute("DrawMediaStageSurface")
        End Function

        Private Shared Function HasCompositionParameterRoute(methodName As String) As Boolean
            Dim flags As BindingFlags = BindingFlags.Instance Or BindingFlags.Static Or BindingFlags.NonPublic Or BindingFlags.Public
            For Each method As MethodInfo In GetType(MASImageViewer).GetMethods(flags)
                If Not String.Equals(method.Name, methodName, StringComparison.Ordinal) Then Continue For
                For Each parameter As ParameterInfo In method.GetParameters()
                    If parameter.ParameterType Is GetType(MASComponentSurfaceMaterialComposition) Then Return True
                Next
            Next

            Return False
        End Function

        Private Shared Function CheckNoLegacyMediaPainterPath() As Boolean
            Dim assembly As Assembly = GetType(MASImageViewer).Assembly
            Return assembly.GetType("Nexamas.UI.Components.MASMediaToolbarPainter", False, False) Is Nothing AndAlso
                   assembly.GetType("Nexamas.UI.Components.MASMediaFooterPainter", False, False) Is Nothing AndAlso
                   assembly.GetType("Nexamas.UI.Components.MASMediaChromePainter", False, False) Is Nothing AndAlso
                   assembly.GetType("Nexamas.UI.Components.MASMediaSurfacePainter", False, False) Is Nothing AndAlso
                   assembly.GetType("Nexamas.UI.Components.MASMediaViewportPainter", False, False) Is Nothing
        End Function

        Private Shared Function CheckNoMediaShellLiteralInImageViewer() As Boolean
            Dim mediaShellLiteral As String = MASSurfaceMaterialIds.MediaShell
            Dim flags As BindingFlags = BindingFlags.Instance Or BindingFlags.Static Or BindingFlags.NonPublic Or BindingFlags.Public Or BindingFlags.DeclaredOnly

            For Each method As MethodInfo In GetType(MASImageViewer).GetMethods(flags)
                If MethodContainsStringLiteral(method, mediaShellLiteral) Then Return False
            Next

            Return True
        End Function

        Private Shared Function MethodContainsStringLiteral(method As MethodInfo,
                                                            literal As String) As Boolean
            If method Is Nothing Then Return False
            Dim body As MethodBody = method.GetMethodBody()
            If body Is Nothing Then Return False

            Dim il As Byte() = body.GetILAsByteArray()
            If il Is Nothing OrElse il.Length < 5 Then Return False

            For i As Integer = 0 To il.Length - 5
                If il(i) <> &H72 Then Continue For

                Dim token As Integer = BitConverter.ToInt32(il, i + 1)
                Try
                    Dim value As String = method.Module.ResolveString(token)
                    If String.Equals(value, literal, StringComparison.Ordinal) Then Return True
                Catch ex As ArgumentException
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDiagnosticOnly(ex, "MASImageViewerSurfaceContractAudit.ContainsLdstr.Argument")
                Catch ex As InvalidOperationException
                    Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDiagnosticOnly(ex, "MASImageViewerSurfaceContractAudit.ContainsLdstr.InvalidOperation")
                End Try
            Next

            Return False
        End Function

        Private Shared Function CheckProfileSwitchProof(defaultRootKey As String,
                                                       defaultToolbarKey As String,
                                                       defaultViewportKey As String,
                                                       defaultFooterKey As String,
                                                       defaultOverlayKey As String) As Boolean
            Dim graphiteComposition As MASComponentSurfaceMaterialComposition = MASImageViewerSurfacePolicy.CreateComposition(MASSurfaceMaterialProfileIds.GraphiteChrome)
            Dim graphiteRootKey As String = ResolveMaterialKey(graphiteComposition, MASComponentSurfaceRegion.Root)
            Dim graphiteToolbarKey As String = ResolveMaterialKey(graphiteComposition, MASComponentSurfaceRegion.Toolbar)
            Dim graphiteViewportKey As String = ResolveMaterialKey(graphiteComposition, MASComponentSurfaceRegion.Viewport)
            Dim graphiteFooterKey As String = ResolveMaterialKey(graphiteComposition, MASComponentSurfaceRegion.Footer)
            Dim graphiteOverlayKey As String = ResolveMaterialKey(graphiteComposition, MASComponentSurfaceRegion.Overlay)

            If Not HasOfficialMaterial(graphiteRootKey) OrElse Not HasOfficialMaterial(graphiteToolbarKey) OrElse Not HasOfficialMaterial(graphiteViewportKey) OrElse Not HasOfficialMaterial(graphiteFooterKey) OrElse Not HasOfficialMaterial(graphiteOverlayKey) Then Return False
            If Not HasIndependentMaterialDistribution(graphiteRootKey, graphiteToolbarKey, graphiteViewportKey, graphiteFooterKey, graphiteOverlayKey) Then Return False

            Return Not Same(defaultRootKey, graphiteRootKey) OrElse
                   Not Same(defaultToolbarKey, graphiteToolbarKey) OrElse
                   Not Same(defaultViewportKey, graphiteViewportKey) OrElse
                   Not Same(defaultFooterKey, graphiteFooterKey) OrElse
                   Not Same(defaultOverlayKey, graphiteOverlayKey)
        End Function

        Private Shared Function Evidence(rootKey As String,
                                         toolbarKey As String,
                                         viewportKey As String,
                                         footerKey As String,
                                         overlayKey As String) As IReadOnlyList(Of String)
            Return New ReadOnlyCollection(Of String)(New List(Of String) From {
                "Root -> " & Normalize(rootKey),
                "Toolbar -> " & Normalize(toolbarKey),
                "Viewport -> " & Normalize(viewportKey),
                "Footer -> " & Normalize(footerKey),
                "Overlay -> " & Normalize(overlayKey),
                "Expected default map -> PlatformDefault / MediaCommandRail / FrostedGlass / MediaFooterChrome / MediaToolbarGlass",
                "PanelShell root material comes from MASImageViewerSurfacePolicy",
                "Toolbar route carries MASComponentSurfaceMaterialComposition",
                "Viewport/Stage route carries MASComponentSurfaceMaterialComposition",
                "Footer route carries MASComponentSurfaceMaterialComposition",
                "Legacy MASMediaToolbarPainter/MASMediaFooterPainter/MASMediaChromePainter/MASMediaSurfacePainter/MASMediaViewportPainter types are absent",
                "MASImageViewer compiled methods contain no MediaShell string literal",
                "Default profile id: " & MASImageViewerSurfacePolicy.DefaultProfileId,
                "Alternate profile switch proof: " & MASSurfaceMaterialProfileIds.GraphiteChrome
            })
        End Function

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

        Private Shared Function Same(left As String, right As String) As Boolean
            Return String.Equals(Normalize(left), Normalize(right), StringComparison.Ordinal)
        End Function
    End Class

End Namespace
