package config

import (
	"os"
	"path/filepath"
	"strings"
	"testing"
)

// A real bcrypt hash for "correct horse" — full of `$word` sequences ($2a, $10, and a $-laden salt)
// that os.ExpandEnv would each replace with an (empty) env value, silently corrupting the hash.
const bcryptHash = `$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy`

func minimalYAML(passwordHash string) string {
	return `customer:
  id: demo
  domain: demo.example.com
web:
  password_hash: "` + passwordHash + `"
`
}

// TestLoadFromBytes_BcryptHashIntact is the F-C2-1 headline red-proof: a bcrypt password_hash must
// survive config load BYTE-IDENTICAL. On the pre-fix code (os.ExpandEnv over the whole file) the
// `$2a$`/`$10$`/`$…salt` segments get expanded to empty → the stored hash is corrupted → silent
// auth breakage. This test FAILS on that pre-fix path.
func TestLoadFromBytes_BcryptHashIntact(t *testing.T) {
	// Make the corruption visible if ExpandEnv ever creeps back: set env vars matching hash segments.
	t.Setenv("2a", "CORRUPT")
	t.Setenv("10", "CORRUPT")

	cfg, err := LoadFromBytes([]byte(minimalYAML(bcryptHash)))
	if err != nil {
		t.Fatalf("LoadFromBytes: %v", err)
	}
	if cfg.Web.PasswordHash != bcryptHash {
		t.Fatalf("password_hash corrupted on load:\n  want %q\n  got  %q", bcryptHash, cfg.Web.PasswordHash)
	}
}

// TestLoadAndParse_BcryptHashIntact proves the same for the file path (loadAndParse / Load).
func TestLoadAndParse_BcryptHashIntact(t *testing.T) {
	t.Setenv("2a", "CORRUPT")
	dir := t.TempDir()
	p := filepath.Join(dir, "controller.yaml")
	if err := os.WriteFile(p, []byte(minimalYAML(bcryptHash)), 0o600); err != nil {
		t.Fatal(err)
	}
	cfg, err := loadAndParse(p)
	if err != nil {
		t.Fatalf("loadAndParse: %v", err)
	}
	if cfg.Web.PasswordHash != bcryptHash {
		t.Fatalf("password_hash corrupted on file load:\n  want %q\n  got  %q", bcryptHash, cfg.Web.PasswordHash)
	}
}

// TestEnvOverride_PasswordHash proves the sanctioned typed env path still wins (applyEnvOverrides).
func TestEnvOverride_PasswordHash(t *testing.T) {
	override := `$2a$10$differentHASHvalueForOverrideTestXXXXXXXXXXXXXXXXXXXXXXXX`
	t.Setenv("FELHOM_WEB_PASSWORD_HASH", override)
	cfg, err := LoadFromBytes([]byte(minimalYAML(bcryptHash)))
	if err != nil {
		t.Fatalf("LoadFromBytes: %v", err)
	}
	if cfg.Web.PasswordHash != override {
		t.Fatalf("FELHOM_WEB_PASSWORD_HASH override not applied:\n  want %q\n  got  %q", override, cfg.Web.PasswordHash)
	}
}

// TestLiteralDollarVarPreserved documents the behavior change: a literal ${VAR} in a value is now
// kept verbatim (no file-level expansion). Session secrets or comments with `$` survive intact.
func TestLiteralDollarVarPreserved(t *testing.T) {
	y := `customer:
  id: demo
  domain: demo.example.com
web:
  session_secret: "literal-${NOT_EXPANDED}-value"
`
	cfg, err := LoadFromBytes([]byte(y))
	if err != nil {
		t.Fatalf("LoadFromBytes: %v", err)
	}
	if !strings.Contains(cfg.Web.SessionSecret, "${NOT_EXPANDED}") {
		t.Fatalf("literal ${VAR} was expanded (should be preserved): %q", cfg.Web.SessionSecret)
	}
}
