package cli

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

// runWithSlog executes the given args against rootCmd, capturing the
// slog output (where warnDeprecated writes). It returns the captured
// slog buffer and the command stdout buffer.
func runWithSlog(t *testing.T, args []string, suppressWarnings bool) (slogOut, stdOut string, err error) {
	t.Helper()
	_, cleanup := initTestEnv(t)
	defer cleanup()
	resetRootFlags(t)

	buf, restore := captureSlog(t)
	defer restore()

	if suppressWarnings {
		_ = rootCmd.PersistentFlags().Set("no-deprecation-warnings", "true")
	}

	var out bytes.Buffer
	rootCmd.SetOut(&out)
	rootCmd.SetErr(&out)
	rootCmd.SetArgs(args)
	err = rootCmd.Execute()
	return buf.String(), out.String(), err
}

func TestDeprecationDaemonEmitsWarning(t *testing.T) {
	slogOut, _ := runDaemonHermetic(t, false)
	if !strings.Contains(slogOut, "orca daemon is deprecated in v0.9") {
		t.Errorf("expected daemon deprecation warning, got:\n%s", slogOut)
	}
}

func TestDeprecationCertCAInitEmitsWarning(t *testing.T) {
	slogOut, _, err := runWithSlog(t, []string{"cert", "ca-init", "--cn", "dep-test"}, false)
	if err != nil {
		t.Fatalf("cert ca-init: %v", err)
	}
	if !strings.Contains(slogOut, "orca cert ca-init is deprecated") {
		t.Errorf("expected cert ca-init deprecation warning, got:\n%s", slogOut)
	}
	if !strings.Contains(slogOut, "step-ca") {
		t.Errorf("deprecation warning should mention step-ca, got:\n%s", slogOut)
	}
}

func TestDeprecationCertGenEmitsWarning(t *testing.T) {
	// gen requires a CA; we only assert the warning fires (before the
	// error path).
	slogOut, _, _ := runWithSlog(t, []string{"cert", "gen", "--cn", "dep-gen"}, false)
	if !strings.Contains(slogOut, "orca cert gen is deprecated") {
		t.Errorf("expected cert gen deprecation warning, got:\n%s", slogOut)
	}
}

func TestDeprecationCertRenewEmitsWarning(t *testing.T) {
	// renew requires a CA; we only assert the warning fires (before the
	// error path).
	slogOut, _, _ := runWithSlog(t, []string{"cert", "renew"}, false)
	if !strings.Contains(slogOut, "orca cert renew is deprecated") {
		t.Errorf("expected cert renew deprecation warning, got:\n%s", slogOut)
	}
}

func TestDeprecationCertShowNoWarning(t *testing.T) {
	slogOut, _, err := runWithSlog(t, []string{"cert", "show"}, false)
	// show may fail if no cert exists; we only assert no deprecation.
	_ = err
	if strings.Contains(slogOut, "deprecated") {
		t.Errorf("cert show must NOT emit deprecation warning, got:\n%s", slogOut)
	}
}

func TestDeprecationCertFingerprintNoWarning(t *testing.T) {
	// Need a CA first so fingerprint has something to read.
	_, cleanup := initTestEnv(t)
	defer cleanup()
	resetRootFlags(t)
	var b bytes.Buffer
	rootCmd.SetOut(&b)
	rootCmd.SetErr(&b)
	rootCmd.SetArgs([]string{"cert", "ca-init", "--cn", "fp-test"})
	if err := rootCmd.Execute(); err != nil {
		t.Fatalf("cert ca-init: %v", err)
	}

	slogBuf, restore := captureSlog(t)
	defer restore()

	resetRootFlags(t)
	var out bytes.Buffer
	rootCmd.SetOut(&out)
	rootCmd.SetErr(&out)
	rootCmd.SetArgs([]string{"cert", "fingerprint", "--which", "ca"})
	_ = rootCmd.Execute()

	if strings.Contains(slogBuf.String(), "deprecated") {
		t.Errorf("cert fingerprint must NOT emit deprecation warning, got:\n%s", slogBuf.String())
	}
}

func TestDeprecationJobRunHCLEmitsWarning(t *testing.T) {
	dir := t.TempDir()
	specPath := filepath.Join(dir, "old-spec.hcl")
	if err := os.WriteFile(specPath, []byte(`job "true" {}
task "t" {
  command = "/bin/true"
}
`), 0o644); err != nil {
		t.Fatalf("write spec: %v", err)
	}
	slogOut, _, err := runWithSlog(t, []string{"job", "run", specPath}, false)
	if err != nil {
		t.Fatalf("job run: %v", err)
	}
	if !strings.Contains(slogOut, ".hcl jobspec is legacy") {
		t.Errorf("expected .hcl deprecation warning, got:\n%s", slogOut)
	}
	if !strings.Contains(slogOut, "R-013") {
		t.Errorf("deprecation warning should reference R-013, got:\n%s", slogOut)
	}
}

func TestDeprecationJobRunMDNoWarning(t *testing.T) {
	dir := t.TempDir()
	specPath := filepath.Join(dir, "spec.md")
	if err := os.WriteFile(specPath, []byte("---\nkind: Workload\nname: md-job\n---\n"), 0o644); err != nil {
		t.Fatalf("write spec: %v", err)
	}
	slogOut, _, _ := runWithSlog(t, []string{"job", "run", specPath}, false)
	if strings.Contains(slogOut, ".hcl jobspec is legacy") {
		t.Errorf(".md jobspec must NOT emit .hcl deprecation warning, got:\n%s", slogOut)
	}
}

func TestDeprecationWarningsSuppressedByFlag(t *testing.T) {
	// daemon
	slogOut, _ := runDaemonHermetic(t, true)
	if strings.Contains(slogOut, "deprecated in v0.9") {
		t.Errorf("--no-deprecation-warnings should suppress daemon warning, got:\n%s", slogOut)
	}

	// cert ca-init
	slogOut2, _, err := runWithSlog(t, []string{"cert", "ca-init", "--cn", "sup-test"}, true)
	if err != nil {
		t.Fatalf("cert ca-init: %v", err)
	}
	if strings.Contains(slogOut2, "deprecated") {
		t.Errorf("--no-deprecation-warnings should suppress cert warning, got:\n%s", slogOut2)
	}

	// job run .hcl
	dir := t.TempDir()
	specPath := filepath.Join(dir, "old-spec.hcl")
	if err := os.WriteFile(specPath, []byte(`job "true" {}
task "t" {
  command = "/bin/true"
}
`), 0o644); err != nil {
		t.Fatalf("write spec: %v", err)
	}
	slogOut3, _, err := runWithSlog(t, []string{"job", "run", specPath}, true)
	if err != nil {
		t.Fatalf("job run: %v", err)
	}
	if strings.Contains(slogOut3, "deprecated") {
		t.Errorf("--no-deprecation-warnings should suppress .hcl warning, got:\n%s", slogOut3)
	}
}
