package pipeline

import (
	"context"
	"testing"

	"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
)

func TestTerminalDiagnosticGroupsDiscardSupersededAttemptDiagnostics(t *testing.T) {
	terminal, err := runProducerAttempts(context.Background(), producerAttemptConfig{Retries: 1, Policy: DefaultValidationPolicy()}, func(_ context.Context, request producerAttemptRequest) (producerAttemptOutput, error) {
		if request.Number == 1 {
			return producerAttemptOutput{Value: "first", Diagnostics: []contracts.ProducerDiagnostic{producerDiagnostic("discarded", "discarded")}, Candidate: attemptCandidate(t, "first")}, nil
		}
		return producerAttemptOutput{Value: "second", Diagnostics: []contracts.ProducerDiagnostic{producerDiagnostic("terminal", "terminal")}}, nil
	}, func(_ context.Context, output producerAttemptOutput) (validationReport, error) {
		if output.Value == "first" {
			return validationReport{records: []validationRecord{{validatorName: "validator", outcome: validationRejected, reasonCode: "invalid", correctionGuidance: "Correct it."}}}, nil
		}
		return validationReport{}, nil
	})
	if err != nil {
		t.Fatalf("runProducerAttempts() error = %v", err)
	}
	groups, err := terminalDiagnosticGroups(terminal, contracts.DiagnosticOrigin{Stage: contracts.DiagnosticOriginStageMerge, StepID: "step", LaneID: "lane", ModuleKey: "module"}, nil)
	if err != nil {
		t.Fatalf("terminalDiagnosticGroups() error = %v", err)
	}
	if len(groups) != 1 || groups[0].Samples[0].Scope != "terminal" {
		t.Fatalf("groups = %#v, want only terminal attempt diagnostics", groups)
	}
}

func TestTerminalDiagnosticGroupsPreserveValidatorOrigin(t *testing.T) {
	terminal := producerAttemptTerminal{Validation: validationReport{records: []validationRecord{{
		validatorName: "dnd/spells/source-relatedness",
		outcome:       validationApproved,
		diagnostics:   []contracts.ProducerDiagnostic{producerDiagnostic("spells[0]", "not found")},
	}}}}
	groups, err := terminalDiagnosticGroups(terminal, contracts.DiagnosticOrigin{Stage: contracts.DiagnosticOriginStageExtract, StepID: "extract", LaneID: "spells", ModuleKey: "dnd/spells"}, nil)
	if err != nil {
		t.Fatalf("terminalDiagnosticGroups() error = %v", err)
	}
	if len(groups) != 1 || groups[0].Origin.ValidatorKey != "dnd/spells/source-relatedness" {
		t.Fatalf("groups = %#v, want validator origin", groups)
	}
}

func TestAppendDiagnosticGroupsRetainsOnlyStructuredDiagnostics(t *testing.T) {
	output := RunOutput{}
	appendDiagnosticGroups(&output, []contracts.DiagnosticGroup{{
		Disposition:     contracts.DiagnosticDispositionAdvisory,
		Category:        contracts.DiagnosticCategoryDataQuality,
		ReasonCode:      "source_unrelated",
		Origin:          contracts.DiagnosticOrigin{Stage: contracts.DiagnosticOriginStageExtract, StepID: "extract", LaneID: "spells", ModuleKey: "dnd/spells"},
		OccurrenceCount: 2,
		Samples:         []contracts.DiagnosticSample{{Scope: "spells[0]", Message: "not found"}, {Scope: "spells[1]", Message: "also not found"}},
	}})
	if err := finalizeDiagnostics(&output); err != nil {
		t.Fatalf("finalizeDiagnostics() error = %v", err)
	}
	if len(output.Diagnostics.Groups) != 1 || output.Diagnostics.Groups[0].OccurrenceCount != 2 {
		t.Fatalf("diagnostics = %#v, want grouped collection", output.Diagnostics)
	}
}

func producerDiagnostic(scope string, message string) contracts.ProducerDiagnostic {
	return contracts.ProducerDiagnostic{
		Disposition:     contracts.DiagnosticDispositionAdvisory,
		Category:        contracts.DiagnosticCategoryDataQuality,
		ReasonCode:      "source_unrelated",
		OccurrenceCount: 1,
		Samples:         []contracts.DiagnosticSample{{Scope: scope, Message: message}},
	}
}
