package stacks

import (
	"io"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"testing"
)

// newSecretGenManager builds a Manager with one stack whose .felhom.yml declares the O4 test
// fields: a generatable resettable secret, a data-key, and a spec-less secret.
func newSecretGenManager(t *testing.T) *Manager {
	t.Helper()
	stackDir := filepath.Join(t.TempDir(), "app")
	if err := os.MkdirAll(stackDir, 0755); err != nil {
		t.Fatal(err)
	}
	meta := `display_name: App
deploy_fields:
  - env_var: DB_PASSWORD
    type: secret
    generate: "password:24"
  - env_var: SECRET_KEY
    type: secret
    generate: "hex:32"
    data_key: true
  - env_var: ADMIN_TOKEN
    type: secret
  - env_var: SUBDOMAIN
    type: subdomain
    default: app
`
	if err := os.WriteFile(filepath.Join(stackDir, ".felhom.yml"), []byte(meta), 0644); err != nil {
		t.Fatal(err)
	}
	return &Manager{
		logger: log.New(io.Discard, "", 0),
		stacks: map[string]*Stack{
			"app": {Name: "app", ComposePath: filepath.Join(stackDir, "docker-compose.yml")},
		},
	}
}

// TestGenerateSecretForField covers the O4 generator seam's contract: spec-conformant values for
// resettable secrets, and REFUSAL for data-keys (frozen fail-closed territory), spec-less fields,
// non-secret fields, and unknown stacks/vars.
func TestGenerateSecretForField(t *testing.T) {
	m := newSecretGenManager(t)

	t.Run("resettable secret with spec → spec-conformant value", func(t *testing.T) {
		v, ok := m.GenerateSecretForField("app", "DB_PASSWORD")
		if !ok {
			t.Fatal("expected generation for DB_PASSWORD (generate: password:24)")
		}
		if len(v) != 24 || !regexp.MustCompile(`^[A-Za-z0-9]+$`).MatchString(v) {
			t.Errorf("value does not conform to password:24 (len=%d)", len(v))
		}
		// Distinct per call (crypto/rand-backed, not a constant).
		if v2, _ := m.GenerateSecretForField("app", "DB_PASSWORD"); v2 == v {
			t.Error("two generations returned the same value")
		}
	})

	t.Run("data-key → REFUSED even with a generate spec", func(t *testing.T) {
		if v, ok := m.GenerateSecretForField("app", "SECRET_KEY"); ok || v != "" {
			t.Error("a data-encrypting key must NEVER be generated")
		}
	})

	t.Run("no generate spec → refused", func(t *testing.T) {
		if _, ok := m.GenerateSecretForField("app", "ADMIN_TOKEN"); ok {
			t.Error("spec-less secret must not be generated (Scenario G: proceed-with-warn instead)")
		}
	})

	t.Run("non-secret field / unknown var / unknown stack → refused", func(t *testing.T) {
		if _, ok := m.GenerateSecretForField("app", "SUBDOMAIN"); ok {
			t.Error("non-secret field must not be generated")
		}
		if _, ok := m.GenerateSecretForField("app", "NOPE"); ok {
			t.Error("unknown env var must not be generated")
		}
		if _, ok := m.GenerateSecretForField("ghost", "DB_PASSWORD"); ok {
			t.Error("unknown stack must not be generated")
		}
	})
}
