Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.Certification

Namespace Nexamas.UI.Verification

    ''' <summary>
    ''' Builds the descriptor-level read model used by the official Render Verification dashboard.
    ''' </summary>
    ''' <remarks>
    ''' The builder does not introduce a second verification path. It joins the existing MASQualityComponentCoverageMap,
    ''' MASRenderVerificationCoverageAudit, and MASRenderVerificationSnapshot so the dashboard can show every registered
    ''' component descriptor and the exact proof route that currently covers it.
    ''' </remarks>
    Friend NotInheritable Class MASRenderVerificationElementCoverageBuilder

        Private Sub New()
        End Sub

        Friend Shared Function BuildCurrent(snapshot As MASRenderVerificationSnapshot) As MASRenderVerificationElementCoverageReport
            Dim coverage As MASQualityComponentCoverageReport = MASQualityComponentCoverageMap.BuildCurrent()
            Dim graph As MASRenderVerificationCoverageReport = MASRenderVerificationCoverageAudit.Build(MASRenderVerificationTargetCatalog.CreateAllTargets(), coverage)
            Return Build(coverage, graph, snapshot)
        End Function

        Friend Shared Function Build(componentCoverage As MASQualityComponentCoverageReport,
                                     graphReport As MASRenderVerificationCoverageReport,
                                     snapshot As MASRenderVerificationSnapshot) As MASRenderVerificationElementCoverageReport
            Dim entries As New List(Of MASRenderVerificationElementCoverageEntry)()
            Dim snapshotIndex As SnapshotIndex = SnapshotIndex.Build(snapshot)

            If componentCoverage Is Nothing OrElse componentCoverage.Entries Is Nothing Then
                Return New MASRenderVerificationElementCoverageReport(entries, graphReport)
            End If

            For Each coverageEntry As MASQualityComponentCoverageEntry In componentCoverage.Entries
                If coverageEntry Is Nothing Then Continue For
                entries.Add(CreateEntry(coverageEntry, snapshotIndex))
            Next

            Return New MASRenderVerificationElementCoverageReport(entries, graphReport)
        End Function

        Private Shared Function CreateEntry(coverageEntry As MASQualityComponentCoverageEntry,
                                            snapshotIndex As SnapshotIndex) As MASRenderVerificationElementCoverageEntry
            If coverageEntry.HasBlockingGap Then
                Return New MASRenderVerificationElementCoverageEntry(
                    coverageEntry.ComponentTypeName,
                    coverageEntry.ComponentFullName,
                    coverageEntry.CategoryName,
                    coverageEntry.CoverageKind,
                    coverageEntry.EvidenceKey,
                    coverageEntry.TargetId,
                    coverageEntry.ScenarioId,
                    MASRenderVerificationElementCoverageState.Unclassified,
                    "MissingCoverage",
                    Nothing,
                    "Component coverage map could not classify this descriptor into a trusted proof route.")
            End If

            Dim visualEntry As MASRenderVerificationEntry = ResolveVisualEntry(coverageEntry, snapshotIndex)
            Dim state As MASRenderVerificationElementCoverageState = ResolveState(coverageEntry, visualEntry)
            Dim targetId As String = If(String.IsNullOrWhiteSpace(coverageEntry.TargetId), ResolveProofTargetId(coverageEntry.CoverageKind), coverageEntry.TargetId)
            Dim scenarioId As String = If(String.IsNullOrWhiteSpace(coverageEntry.ScenarioId) AndAlso visualEntry IsNot Nothing, visualEntry.ScenarioId, coverageEntry.ScenarioId)
            Dim evidenceRouteText As String = ResolveEvidenceRouteText(coverageEntry, visualEntry, state)
            Dim summary As String = BuildSummary(coverageEntry, visualEntry, state, evidenceRouteText)

            Return New MASRenderVerificationElementCoverageEntry(
                coverageEntry.ComponentTypeName,
                coverageEntry.ComponentFullName,
                coverageEntry.CategoryName,
                coverageEntry.CoverageKind,
                coverageEntry.EvidenceKey,
                targetId,
                scenarioId,
                state,
                evidenceRouteText,
                visualEntry,
                summary)
        End Function

        Private Shared Function ResolveState(coverageEntry As MASQualityComponentCoverageEntry,
                                             visualEntry As MASRenderVerificationEntry) As MASRenderVerificationElementCoverageState
            If coverageEntry.CoverageKind = MASQualityComponentCoverageKind.DirectRenderScenario OrElse
               coverageEntry.CoverageKind = MASQualityComponentCoverageKind.FamilyRenderScenario Then
                If visualEntry Is Nothing Then Return MASRenderVerificationElementCoverageState.MissingSnapshot
                Return ResolveSnapshotState(visualEntry)
            End If

            If visualEntry IsNot Nothing Then
                Return ResolveSnapshotState(visualEntry)
            End If

            Return MASRenderVerificationElementCoverageState.ContractProof
        End Function

        Private Shared Function ResolveSnapshotState(entry As MASRenderVerificationEntry) As MASRenderVerificationElementCoverageState
            If entry Is Nothing Then Return MASRenderVerificationElementCoverageState.MissingSnapshot
            Select Case entry.Outcome
                Case MASRenderVerificationOutcome.Passed
                    Return MASRenderVerificationElementCoverageState.Matched
                Case MASRenderVerificationOutcome.BaselineSeeded
                    Return MASRenderVerificationElementCoverageState.VisualReview
                Case MASRenderVerificationOutcome.Failed
                    Return MASRenderVerificationElementCoverageState.Changed
                Case Else
                    Return MASRenderVerificationElementCoverageState.Invalid
            End Select
        End Function

        Private Shared Function ResolveVisualEntry(coverageEntry As MASQualityComponentCoverageEntry,
                                                   snapshotIndex As SnapshotIndex) As MASRenderVerificationEntry
            If snapshotIndex Is Nothing Then Return Nothing

            If Not String.IsNullOrWhiteSpace(coverageEntry.ScenarioId) Then
                Dim byScenario As MASRenderVerificationEntry = snapshotIndex.FindByScenarioId(coverageEntry.ScenarioId)
                If byScenario IsNot Nothing Then Return byScenario
            End If

            If Not String.IsNullOrWhiteSpace(coverageEntry.TargetId) Then
                Dim byTarget As MASRenderVerificationEntry = snapshotIndex.FindByTargetId(coverageEntry.TargetId)
                If byTarget IsNot Nothing Then Return byTarget
            End If

            Dim proofTargetId As String = ResolveProofTargetId(coverageEntry.CoverageKind)
            If Not String.IsNullOrWhiteSpace(proofTargetId) Then
                Return snapshotIndex.FindByTargetId(proofTargetId)
            End If

            Return Nothing
        End Function

        Private Shared Function ResolveProofTargetId(kind As MASQualityComponentCoverageKind) As String
            Select Case kind
                Case MASQualityComponentCoverageKind.SurfaceMaterialProof
                    Return "surface-material-proof"
                Case MASQualityComponentCoverageKind.SizeLayoutContractProof
                    Return "responsive-layout-matrix"
                Case MASQualityComponentCoverageKind.InteractionStateProof
                    Return "core-controls"
                Case MASQualityComponentCoverageKind.SystemInventoryProof
                    Return String.Empty
                Case Else
                    Return String.Empty
            End Select
        End Function

        Private Shared Function ResolveEvidenceRouteText(coverageEntry As MASQualityComponentCoverageEntry,
                                                        visualEntry As MASRenderVerificationEntry,
                                                        state As MASRenderVerificationElementCoverageState) As String
            If coverageEntry Is Nothing Then Return "MissingCoverage"

            If coverageEntry.CoverageKind = MASQualityComponentCoverageKind.DirectRenderScenario OrElse
               coverageEntry.CoverageKind = MASQualityComponentCoverageKind.FamilyRenderScenario Then
                If visualEntry Is Nothing OrElse state = MASRenderVerificationElementCoverageState.MissingSnapshot Then Return "MissingVisualEvidence"
                Return "VisualCaptured"
            End If

            If visualEntry IsNot Nothing Then Return "RuntimeProofWithVisualRow"
            If coverageEntry.CoverageKind = MASQualityComponentCoverageKind.SystemInventoryProof Then Return "InventoryReadModelProof"
            Return "ContractProofOnly"
        End Function

        Private Shared Function BuildSummary(coverageEntry As MASQualityComponentCoverageEntry,
                                             visualEntry As MASRenderVerificationEntry,
                                             state As MASRenderVerificationElementCoverageState,
                                             evidenceRouteText As String) As String
            Dim route As String = If(String.IsNullOrWhiteSpace(coverageEntry.Summary), "Coverage route is registered.", coverageEntry.Summary)
            If visualEntry Is Nothing Then
                If coverageEntry.CoverageKind = MASQualityComponentCoverageKind.DirectRenderScenario OrElse
                   coverageEntry.CoverageKind = MASQualityComponentCoverageKind.FamilyRenderScenario Then
                    Return route & " Evidence route: " & evidenceRouteText & ". A visual capture is expected for this descriptor route, but no snapshot row was joined."
                End If

                Return route & " Evidence route: " & evidenceRouteText & ". No PNG row is required for this explicit contract-only proof route."
            End If

            Return route & " Evidence route: " & evidenceRouteText & ". Snapshot row: " & visualEntry.TargetName & " / " & visualEntry.DisplayName & " / " & state.ToString() & "."
        End Function

        Private NotInheritable Class SnapshotIndex
            Private ReadOnly _byScenarioId As Dictionary(Of String, MASRenderVerificationEntry)
            Private ReadOnly _byTargetId As Dictionary(Of String, MASRenderVerificationEntry)

            Private Sub New(byScenarioId As Dictionary(Of String, MASRenderVerificationEntry),
                            byTargetId As Dictionary(Of String, MASRenderVerificationEntry))
                _byScenarioId = byScenarioId
                _byTargetId = byTargetId
            End Sub

            Friend Shared Function Build(snapshot As MASRenderVerificationSnapshot) As SnapshotIndex
                Dim byScenarioId As New Dictionary(Of String, MASRenderVerificationEntry)(StringComparer.OrdinalIgnoreCase)
                Dim byTargetId As New Dictionary(Of String, MASRenderVerificationEntry)(StringComparer.OrdinalIgnoreCase)

                If snapshot IsNot Nothing AndAlso snapshot.Entries IsNot Nothing Then
                    For Each entry As MASRenderVerificationEntry In snapshot.Entries
                        If entry Is Nothing Then Continue For
                        If Not String.IsNullOrWhiteSpace(entry.ScenarioId) AndAlso Not byScenarioId.ContainsKey(entry.ScenarioId) Then byScenarioId.Add(entry.ScenarioId, entry)
                        If Not String.IsNullOrWhiteSpace(entry.TargetId) Then
                            Dim existing As MASRenderVerificationEntry = Nothing
                            If Not byTargetId.TryGetValue(entry.TargetId, existing) OrElse IsBetterRepresentative(entry, existing) Then
                                byTargetId(entry.TargetId) = entry
                            End If
                        End If
                    Next
                End If

                Return New SnapshotIndex(byScenarioId, byTargetId)
            End Function

            Friend Function FindByScenarioId(scenarioId As String) As MASRenderVerificationEntry
                If String.IsNullOrWhiteSpace(scenarioId) Then Return Nothing
                Dim result As MASRenderVerificationEntry = Nothing
                If _byScenarioId.TryGetValue(scenarioId, result) Then Return result
                Return Nothing
            End Function

            Friend Function FindByTargetId(targetId As String) As MASRenderVerificationEntry
                If String.IsNullOrWhiteSpace(targetId) Then Return Nothing
                Dim result As MASRenderVerificationEntry = Nothing
                If _byTargetId.TryGetValue(targetId, result) Then Return result
                Return Nothing
            End Function

            Private Shared Function IsBetterRepresentative(candidate As MASRenderVerificationEntry,
                                                           current As MASRenderVerificationEntry) As Boolean
                If current Is Nothing Then Return True
                If candidate Is Nothing Then Return False

                Dim candidateScore As Integer = Score(candidate)
                Dim currentScore As Integer = Score(current)
                If candidateScore <> currentScore Then Return candidateScore > currentScore

                Return String.Compare(candidate.ScenarioId, current.ScenarioId, StringComparison.OrdinalIgnoreCase) < 0
            End Function

            Private Shared Function Score(entry As MASRenderVerificationEntry) As Integer
                If entry Is Nothing Then Return 0
                Select Case entry.Outcome
                    Case MASRenderVerificationOutcome.Passed
                        Return 4
                    Case MASRenderVerificationOutcome.BaselineSeeded
                        Return 3
                    Case MASRenderVerificationOutcome.Failed
                        Return 2
                    Case Else
                        Return 1
                End Select
            End Function
        End Class

    End Class

End Namespace
