package oauthroutes

import (
	"encoding/json"
	"os"
	"path/filepath"
	"testing"
)

// patternsPassthroughGoldenPath is the checked-in regression snapshot for the
// non-"/services/data" and empty-prefix pass-through behavior of ValidatePattern,
// CanonicalPattern, and ValidatePatterns. Regenerate with UPDATE_GOLDEN=1;
// otherwise the test asserts the live functions still produce it byte-for-byte.
const patternsPassthroughGoldenPath = "testdata/patterns_passthrough_golden.json"

// TestPatternsPassthroughGolden is a Phase-2 L0-B capture-and-freeze regression.
// It drives the prefix-parameterized Family surface (Validate/Canonical/
// ValidatePatterns) under the Salesforce route family over inputs that are NOT in
// that family — including the empty string — and freezes the exact output (error
// presence + message, canonical rewrite) against
// testdata/patterns_passthrough_golden.json.
//
// Anything outside the family prefix (and the empty string) is a silent
// pass-through: ValidatePattern returns nil and CanonicalPattern returns the
// input verbatim. This golden pins that non-family pass-through behavior so a
// future refactor CANNOT silently change how a non-family path is validated or
// canonicalized. Do NOT modify patterns.go to satisfy this test.
//
// This adds no production behavior and touches no non-test .go file; it only
// reads the exported Family API.
//
// Regenerate:  UPDATE_GOLDEN=1 GOWORK=off go test ./pkg/oauthroutes/ -run PatternsPassthroughGolden
func TestPatternsPassthroughGolden(t *testing.T) {
	// Inputs that are outside the "/services/data/" versioned-route family, plus
	// the empty-prefix / empty-string case. None of these should be treated as a
	// family member today, so all must pass through untouched.
	singleInputs := []string{
		"",                            // empty prefix / empty string
		" ",                           // whitespace-only (still no family prefix)
		"/",                           // bare root
		"/id/:orgId/:userId",          // non-family identity route
		"/services/oauth2/userinfo",   // non-family oauth route
		"/services/data",              // base services-data WITHOUT trailing slash (not the family prefix)
		"/services/datax/v63.0/query", // near-miss prefix that is NOT "/services/data/"
		"relative/path",               // no leading slash at all
		"services/data/v63.0/query",   // family-looking but missing the leading slash -> non-family
	}

	f := NewFamily(testRouteFamilyPrefix)
	out := passthroughGolden{}
	for _, in := range singleInputs {
		out.Single = append(out.Single, passthroughCase{
			Input:            in,
			ValidateErr:      errString(f.ValidatePattern(in)),
			ValidateErrIsNil: f.ValidatePattern(in) == nil,
			Canonical:        f.CanonicalPattern(in),
		})
	}

	// ValidatePatterns over raw fields that tokenize to zero or only non-family
	// patterns -> no error. This pins that the multi-pattern reader also passes
	// non-family / empty fields through.
	multiInputs := []string{
		"",        // empty field -> zero patterns
		"   ,   ", // only delimiters -> zero patterns
		"/id/:orgId/:userId /services/oauth2/userinfo", // all non-family
		"/services/oauth2/userinfo,/id/:orgId/:userId", // comma-delimited non-family
	}
	for _, in := range multiInputs {
		out.Multi = append(out.Multi, passthroughMultiCase{
			Raw:              in,
			ValidateErr:      errString(f.ValidatePatterns(in)),
			ValidateErrIsNil: f.ValidatePatterns(in) == nil,
		})
	}

	got, err := json.MarshalIndent(out, "", "  ")
	if err != nil {
		t.Fatalf("marshal passthrough golden: %v", err)
	}
	got = append(got, '\n')

	if os.Getenv("UPDATE_GOLDEN") == "1" {
		if err := os.MkdirAll(filepath.Dir(patternsPassthroughGoldenPath), 0o755); err != nil {
			t.Fatalf("mkdir testdata: %v", err)
		}
		if err := os.WriteFile(patternsPassthroughGoldenPath, got, 0o644); err != nil {
			t.Fatalf("write golden: %v", err)
		}
		t.Logf("regenerated %s (%d single, %d multi)", patternsPassthroughGoldenPath, len(out.Single), len(out.Multi))
		return
	}

	want, err := os.ReadFile(patternsPassthroughGoldenPath)
	if err != nil {
		t.Fatalf("read golden %s (run with UPDATE_GOLDEN=1 to create): %v", patternsPassthroughGoldenPath, err)
	}
	if string(got) != string(want) {
		t.Fatalf("oauthroutes pass-through golden drifted.\n--- got ---\n%s\n--- want ---\n%s\n"+
			"If this change is intentional (e.g. B2 parameterization), regenerate with UPDATE_GOLDEN=1.", got, want)
	}
}

type passthroughGolden struct {
	Single []passthroughCase      `json:"single"`
	Multi  []passthroughMultiCase `json:"multi"`
}

type passthroughCase struct {
	Input            string `json:"input"`
	ValidateErr      string `json:"validateErr,omitempty"`
	ValidateErrIsNil bool   `json:"validateErrIsNil"`
	Canonical        string `json:"canonical"`
}

type passthroughMultiCase struct {
	Raw              string `json:"raw"`
	ValidateErr      string `json:"validateErr,omitempty"`
	ValidateErrIsNil bool   `json:"validateErrIsNil"`
}

func errString(err error) string {
	if err == nil {
		return ""
	}
	return err.Error()
}
