Imports System
Imports System.Collections.Generic
Imports SkiaSharp

Namespace Nexamas.UI.Verification

    ''' <summary>
    ''' Executes deterministic screenshot capture, persistence, and baseline comparison for render verification targets.
    ''' The runner is capture-handler driven so controls, surfaces, and future gallery hosts can plug in without parallel systems.
    ''' </summary>
    Friend NotInheritable Class MASRenderVerificationRunner

        Private Sub New()
        End Sub

        Friend Shared Function Run(targets As IEnumerable(Of MASRenderVerificationTarget),
                                   store As MASRenderBaselineStore,
                                   capture As MASRenderCaptureHandler,
                                   Optional options As MASRenderVerificationOptions = Nothing,
                                   Optional progress As IProgress(Of MASRenderVerificationProgressInfo) = Nothing) As MASRenderVerificationRunResult
            If capture Is Nothing Then Throw New ArgumentNullException(NameOf(capture))
            If options Is Nothing Then options = New MASRenderVerificationOptions()

            Dim snapshots = New List(Of MASRenderSnapshotResult)()
            Dim diffs = New List(Of MASRenderDiffResult)()
            Dim findings = New List(Of MASRenderVerificationFinding)()
            Dim gate = MASRenderVerificationGate.Evaluate(targets, store)
            findings.AddRange(gate.Findings)

            If Not gate.IsReady Then
                Return New MASRenderVerificationRunResult(snapshots, diffs, findings)
            End If

            store.EnsureDirectories()

            Dim totalScenarios As Integer = CountScenarios(targets)
            Dim completedScenarios As Integer = 0

            For Each target In targets
                If target Is Nothing Then Continue For

                For Each scenario In target.Scenarios
                    If scenario Is Nothing Then Continue For

                    MASRenderVerification.ReportProgress(progress, completedScenarios, totalScenarios, "Capturing " & scenario.DisplayName & "...", target.DisplayName, scenario.DisplayName)

                    Using current As SKBitmap = capture(scenario)
                        If current Is Nothing Then
                            diffs.Add(New MASRenderDiffResult(scenario, MASRenderVerificationOutcome.Invalid, 0, 0, 0, options.DiffSettings, "Capture returned no bitmap."))
                            completedScenarios += 1
                            MASRenderVerification.ReportProgress(progress, completedScenarios, totalScenarios, "Capture returned no bitmap.", target.DisplayName, scenario.DisplayName)
                            Continue For
                        End If

                        If current.Width <> scenario.WidthPx OrElse current.Height <> scenario.HeightPx Then
                            Dim message = "Captured bitmap size does not match scenario. Expected=" & scenario.WidthPx & "x" & scenario.HeightPx & ", Actual=" & current.Width & "x" & current.Height & "."
                            diffs.Add(New MASRenderDiffResult(scenario, MASRenderVerificationOutcome.Invalid, 0, 0, 0, options.DiffSettings, message))
                            completedScenarios += 1
                            MASRenderVerification.ReportProgress(progress, completedScenarios, totalScenarios, "Captured bitmap size was invalid.", target.DisplayName, scenario.DisplayName)
                            Continue For
                        End If

                        Dim currentSnapshot As MASRenderSnapshotResult = store.SaveCurrent(scenario, current)
                        snapshots.Add(currentSnapshot)

                        If Not store.BaselineExists(scenario) Then
                            Dim baselineStatus As String
                            If options.BaselineMode = MASRenderBaselineMode.CreateMissing Then
                                snapshots.Add(store.SaveBaselineFromCurrent(scenario, currentSnapshot))
                                diffs.Add(New MASRenderDiffResult(scenario, MASRenderVerificationOutcome.BaselineSeeded, current.Width * current.Height, 0, 0, options.DiffSettings, "Missing baseline was seeded and is waiting for approval."))
                                baselineStatus = "Seeded missing baseline for " & scenario.DisplayName & "; approval is still required."
                            Else
                                diffs.Add(New MASRenderDiffResult(scenario, MASRenderVerificationOutcome.Failed, current.Width * current.Height, current.Width * current.Height, 255, options.DiffSettings, "Approved baseline is missing."))
                                baselineStatus = "Approved baseline is missing for " & scenario.DisplayName & "."
                            End If

                            completedScenarios += 1
                            MASRenderVerification.ReportProgress(progress, completedScenarios, totalScenarios, baselineStatus, target.DisplayName, scenario.DisplayName)
                            Continue For
                        End If

                        Dim baselineHash As String = store.ComputeBaselineFileHash(scenario)
                        If baselineHash.Length > 0 AndAlso String.Equals(baselineHash, currentSnapshot.Hash, StringComparison.OrdinalIgnoreCase) Then
                            diffs.Add(New MASRenderDiffResult(scenario, MASRenderVerificationOutcome.Passed, current.Width * current.Height, 0, 0, options.DiffSettings, "Screenshot matches approved baseline by persisted PNG hash."))
                        Else
                            Using baseline = store.LoadBaseline(scenario)
                                diffs.Add(MASRenderImageComparer.Compare(scenario, baseline, current, options.DiffSettings))
                            End Using
                        End If

                        completedScenarios += 1
                        MASRenderVerification.ReportProgress(progress, completedScenarios, totalScenarios, "Compared " & scenario.DisplayName & ".", target.DisplayName, scenario.DisplayName)
                    End Using
                Next
            Next

            Return New MASRenderVerificationRunResult(snapshots, diffs, findings)
        End Function
        Private Shared Function CountScenarios(targets As IEnumerable(Of MASRenderVerificationTarget)) As Integer
            If targets Is Nothing Then Return 0

            Dim count As Integer = 0
            For Each target As MASRenderVerificationTarget In targets
                If target Is Nothing Then Continue For

                For Each scenario As MASRenderVerificationScenario In target.Scenarios
                    If scenario IsNot Nothing Then count += 1
                Next
            Next

            Return count
        End Function


    End Class

End Namespace
