package services

// Regression test for the procedural-event placeholder aliases
// (t-paliad-262 Slice A, m/paliad#93 Q7).
//
// The variable bag emits TWO key prefixes for the procedural-event
// namespace:
//
//   - procedural_event.*  (canonical, post-rename)
//   - rule.*              (legacy, @deprecated)
//
// m's lock: keep the legacy aliases forever so lawyer-authored Word
// templates and existing paliad.submission_drafts rows that already
// contain `{{rule.X}}` keep merging correctly.
//
// This test pins the contract: every (canonical, legacy) pair must
// resolve to the same string in the placeholder map, for every value
// of (lang, present-vs-NULL columns). Removing the legacy aliases —
// or letting them drift in value from the canonical — must light up
// here BEFORE the change can land in main.

import (
	"strings"
	"testing"

	"github.com/google/uuid"

	"mgit.msbls.de/m/paliad/internal/models"
)

func TestAddRuleVars_CanonicalAndLegacyAliasesMatch(t *testing.T) {
	t.Parallel()

	// Pairs are (canonical key, legacy key). Order matters only for
	// the assertion message — the test checks string equality both
	// ways round.
	pairs := []struct {
		canonical string
		legacy    string
	}{
		{"procedural_event.code", "rule.submission_code"},
		{"procedural_event.name", "rule.name"},
		{"procedural_event.name_de", "rule.name_de"},
		{"procedural_event.name_en", "rule.name_en"},
		{"procedural_event.legal_source", "rule.legal_source"},
		{"procedural_event.legal_source_pretty", "rule.legal_source_pretty"},
		{"procedural_event.primary_party", "rule.primary_party"},
		{"procedural_event.event_kind", "rule.event_type"},
	}

	// Build a fully-populated rule row. Every nullable column has a
	// distinct non-empty value so missing-value bugs (e.g. the legacy
	// key copying "" while the canonical key copies the real value)
	// would surface.
	code := "dpma.appeal.bgh.begruendung"
	desc := "Rechtsbeschwerdebegründung — § 102 PatG"
	party := "both"
	kind := "filing"
	legal := "DE.PatG.102"
	ruleCode := "§ 102 PatG"

	rule := &models.DeadlineRule{
		ID:             uuid.New(),
		SubmissionCode: &code,
		Name:           "Rechtsbeschwerdebegründung",
		NameEN:         "Appeal brief",
		Description:    &desc,
		PrimaryParty:   &party,
		EventType:      &kind,
		LegalSource:    &legal,
		RuleCode:       &ruleCode,
	}

	for _, lang := range []string{"de", "en"} {
		t.Run(lang, func(t *testing.T) {
			t.Parallel()
			bag := PlaceholderMap{}
			addRuleVars(bag, rule, lang)

			for _, p := range pairs {
				canonicalVal, canonicalOK := bag[p.canonical]
				legacyVal, legacyOK := bag[p.legacy]

				if !canonicalOK {
					t.Errorf("canonical key %q missing from bag (lang=%s); "+
						"Slice A must emit both forms", p.canonical, lang)
				}
				if !legacyOK {
					t.Errorf("legacy alias %q missing from bag (lang=%s); "+
						"removing legacy aliases would break existing Word "+
						"templates that paliad doesn't see — keep the "+
						"emission per m/paliad#93 Q7", p.legacy, lang)
				}
				if canonicalVal != legacyVal {
					t.Errorf("alias drift: %q=%q vs %q=%q (lang=%s)",
						p.canonical, canonicalVal,
						p.legacy, legacyVal, lang)
				}
			}

			// Sanity: the localized name actually localizes (the
			// canonical and legacy `name` keys depend on lang). If
			// this fails the loop above wouldn't catch it (both keys
			// would agree on the wrong language).
			localized := bag["procedural_event.name"]
			if strings.EqualFold(lang, "en") && localized != rule.NameEN {
				t.Errorf("expected EN localized name=%q, got %q",
					rule.NameEN, localized)
			}
			if strings.EqualFold(lang, "de") && localized != rule.Name {
				t.Errorf("expected DE localized name=%q, got %q",
					rule.Name, localized)
			}
		})
	}
}

func TestAddRuleVars_NullableFieldsEmitEmptyOnBothPrefixes(t *testing.T) {
	t.Parallel()

	// A minimal rule with every optional column NULL. The bag must
	// still emit every canonical + legacy key — with the empty
	// string — so downstream merging produces the standard
	// "[KEIN WERT: ...]" marker rather than a broken template.
	rule := &models.DeadlineRule{
		ID:     uuid.New(),
		Name:   "Generic step",
		NameEN: "Generic step",
	}

	bag := PlaceholderMap{}
	addRuleVars(bag, rule, "de")

	mustHave := []string{
		"procedural_event.code", "rule.submission_code",
		"procedural_event.legal_source", "rule.legal_source",
		"procedural_event.legal_source_pretty", "rule.legal_source_pretty",
		"procedural_event.primary_party", "rule.primary_party",
		"procedural_event.event_kind", "rule.event_type",
	}
	for _, key := range mustHave {
		val, ok := bag[key]
		if !ok {
			t.Errorf("key %q missing from bag even with NULL source column; "+
				"derefString must materialize the empty string so the "+
				"merger sees the variable and renders the missing-value "+
				"marker", key)
		}
		if val != "" {
			t.Errorf("key %q = %q, want \"\" (source column was NULL)", key, val)
		}
	}
}
