Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic

Namespace Nexamas.UI.Quality

    ''' <summary>
    ''' Friend-only gate for the remaining control-specific ProductionReady gaps.
    ''' It passes for CompactPreview when gaps are explicit and owned, but it blocks
    ''' ProductionReady for a control until that control's gaps are closed with
    ''' evidence keys.
    ''' </summary>
    Friend NotInheritable Class MASControlSpecificProductionGapGate

        Private Sub New()
        End Sub

        Friend Shared Function Passes() As Boolean
            Return EvaluateFindings().Count = 0
        End Function

        Friend Shared Function AreProductionGapsClosedFor(componentId As String) As Boolean
            Try
                Return MASControlProductionGapManifest.CreateDefault().AllGapsClosedFor(componentId)
            Catch ex As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDiagnosticOnly(ex, "MASControlSpecificProductionGapGate.AreProductionGapsClosedFor")
                Return False
            End Try
        End Function

        Friend Shared Function EvaluateFindings() As IReadOnlyList(Of MASCommercialReadinessFinding)
            Dim findings As New List(Of MASCommercialReadinessFinding)()
            Dim matrix As MASCommercialReadinessMatrix = Nothing
            Dim manifest As MASControlProductionGapManifest = Nothing

            Try
                matrix = MASCommercialReadinessMatrixBuilder.BuildProductControlsMatrix()
            Catch ex As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDiagnosticOnly(ex, "MASControlSpecificProductionGapGate.BuildMatrix")
                findings.Add(New MASCommercialReadinessFinding("production-gaps", "Matrix", MASCommercialReadinessFindingSeverity.Error, "Commercial readiness matrix could not be built for production-gap validation."))
            End Try

            Try
                manifest = MASControlProductionGapManifest.CreateDefault()
            Catch ex As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowDiagnosticOnly(ex, "MASControlSpecificProductionGapGate.CreateManifest")
                findings.Add(New MASCommercialReadinessFinding("production-gaps", "Manifest", MASCommercialReadinessFindingSeverity.Error, "Control-specific production-gap manifest could not be built."))
            End Try

            If manifest Is Nothing Then Return findings

            If Not manifest.HasExpectedProductControlCoverage Then
                findings.Add(New MASCommercialReadinessFinding("production-gaps", "Coverage", MASCommercialReadinessFindingSeverity.Error, "Control-specific production gaps must cover exactly the eight product controls and keep explicit open blockers while controls are CompactPreview."))
            End If

            Dim gapIds As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
            For Each gap As MASControlProductionGapRecord In manifest.Records
                If gap Is Nothing Then
                    findings.Add(New MASCommercialReadinessFinding("production-gaps", "Record", MASCommercialReadinessFindingSeverity.Error, "Control-specific production-gap manifest contains a null record."))
                    Continue For
                End If

                If Not gapIds.Add(gap.GapId) Then
                    findings.Add(New MASCommercialReadinessFinding(gap.ComponentId, "DuplicateGap", MASCommercialReadinessFindingSeverity.Error, "Production gap id is duplicated: " & gap.GapId))
                End If

                If Not gap.IsStructurallyValid Then
                    findings.Add(New MASCommercialReadinessFinding(gap.ComponentId, "GapStructure", MASCommercialReadinessFindingSeverity.Error, gap.ComponentName & " production gap is structurally invalid: " & gap.GapId))
                End If

                If gap.IsClosed AndAlso Not gap.HasClosureEvidence Then
                    findings.Add(New MASCommercialReadinessFinding(gap.ComponentId, "GapEvidence", MASCommercialReadinessFindingSeverity.Error, gap.ComponentName & " has a closed production gap without an evidence key: " & gap.GapId))
                End If

                If matrix IsNot Nothing AndAlso matrix.FindById(gap.ComponentId) Is Nothing Then
                    findings.Add(New MASCommercialReadinessFinding(gap.ComponentId, "MatrixRecord", MASCommercialReadinessFindingSeverity.Error, gap.ComponentName & " has production gaps but no commercial readiness matrix record."))
                End If
            Next

            If matrix IsNot Nothing Then
                For Each record As MASCommercialReadinessRecord In matrix.Records
                    If record Is Nothing Then Continue For

                    Dim gaps As IReadOnlyList(Of MASControlProductionGapRecord) = manifest.FindByComponent(record.Id)
                    If gaps.Count = 0 Then
                        findings.Add(New MASCommercialReadinessFinding(record.Id, "GapCoverage", MASCommercialReadinessFindingSeverity.Error, record.DisplayName & " has no control-specific production-gap records."))
                        Continue For
                    End If

                    If record.Stage = MASCommercialReadinessStage.CompactPreview AndAlso Not manifest.HasOpenGapFor(record.Id) Then
                        findings.Add(New MASCommercialReadinessFinding(record.Id, "PreviewGapBoundary", MASCommercialReadinessFindingSeverity.Error, record.DisplayName & " is CompactPreview but has no open control-specific production gap."))
                    End If

                    If record.Stage = MASCommercialReadinessStage.ProductionReady AndAlso Not manifest.AllGapsClosedFor(record.Id) Then
                        findings.Add(New MASCommercialReadinessFinding(record.Id, "ProductionGapClosure", MASCommercialReadinessFindingSeverity.Error, record.DisplayName & " cannot be ProductionReady until all control-specific production gaps are closed with evidence."))
                    End If
                Next
            End If

            Return findings
        End Function

    End Class

End Namespace
