package cli

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

// clearGlobalEnv neutralizes the BUNNY_ env fallbacks so a test controls
// resolution entirely through flags.
func clearGlobalEnv(t *testing.T) {
	t.Helper()
	for _, k := range []string{"BUNNY_ZONE", "BUNNY_ENDPOINT", "BUNNY_ACCESS_KEY_FILE", "BUNNY_ACCESS_KEY"} {
		t.Setenv(k, "")
	}
}

func writeKeyFile(t *testing.T) string {
	t.Helper()
	p := filepath.Join(t.TempDir(), "key")
	if err := os.WriteFile(p, []byte("secret\n"), 0o600); err != nil {
		t.Fatal(err)
	}
	return p
}

func runMain(args []string) error {
	return newMainCommand().Run(context.Background(), args)
}

func TestMainMissingSubcommand(t *testing.T) {
	clearGlobalEnv(t)
	captureLogs(t)

	var ue usageError
	if err := runMain(nil); !errors.As(err, &ue) {
		t.Fatalf("expected usageError, got %v", err)
	}
}

func TestMainMissingZone(t *testing.T) {
	clearGlobalEnv(t)
	captureLogs(t)

	var ue usageError
	err := runMain([]string{"push"})
	if !errors.As(err, &ue) || !strings.Contains(err.Error(), "zone") {
		t.Fatalf("expected missing-zone usageError, got %v", err)
	}
}

func TestMainMissingAccessKey(t *testing.T) {
	clearGlobalEnv(t)
	captureLogs(t)

	var ue usageError
	err := runMain([]string{"--zone", "z", "push"})
	if !errors.As(err, &ue) || !strings.Contains(err.Error(), "access key") {
		t.Fatalf("expected missing-access-key usageError, got %v", err)
	}
}

func TestMainUnknownSubcommand(t *testing.T) {
	clearGlobalEnv(t)
	captureLogs(t)
	kf := writeKeyFile(t)

	var ue usageError
	err := runMain([]string{"--zone", "z", "--access-key-file", kf, "frob"})
	if !errors.As(err, &ue) || !strings.Contains(err.Error(), "unknown subcommand") {
		t.Fatalf("expected unknown-subcommand usageError, got %v", err)
	}
}

func TestMainDispatchesToPrune(t *testing.T) {
	clearGlobalEnv(t)
	captureLogs(t)
	kf := writeKeyFile(t)

	// A fully-resolved global set reaches dispatch; the missing archive surfaces a
	// plain (non-usage) error, proving parse + validation + dispatch worked.
	err := runMain([]string{"--zone", "z", "--access-key-file", kf, "prune", "no-such.tgz"})
	if err == nil || !strings.Contains(err.Error(), "open archive") {
		t.Fatalf("expected prune dispatch error, got %v", err)
	}
}

func TestMainAccessKeyFromEnv(t *testing.T) {
	clearGlobalEnv(t)
	captureLogs(t)
	t.Setenv("BUNNY_ACCESS_KEY", "literalkey")

	// With no --access-key-file, the literal BUNNY_ACCESS_KEY resolves the key
	// and resolution reaches prune.
	err := runMain([]string{"--zone", "z", "prune", "no-such.tgz"})
	if err == nil || !strings.Contains(err.Error(), "open archive") {
		t.Fatalf("expected prune dispatch error (env access key resolved), got %v", err)
	}
}

func TestMainZoneFromEnv(t *testing.T) {
	clearGlobalEnv(t)
	captureLogs(t)
	t.Setenv("BUNNY_ZONE", "envzone")
	kf := writeKeyFile(t)

	// With zone supplied via env, resolution succeeds and reaches prune.
	err := runMain([]string{"--access-key-file", kf, "prune", "no-such.tgz"})
	if err == nil || !strings.Contains(err.Error(), "open archive") {
		t.Fatalf("expected prune dispatch error (env zone resolved), got %v", err)
	}
}

func TestLookupEnv(t *testing.T) {
	t.Setenv("BUNNY_TEST_LOOKUP", "value")
	if got := lookupEnv("BUNNY_TEST_LOOKUP", "fallback"); got != "value" {
		t.Fatalf("set env: got %q", got)
	}
	t.Setenv("BUNNY_TEST_LOOKUP", "")
	if got := lookupEnv("BUNNY_TEST_LOOKUP", "fallback"); got != "fallback" {
		t.Fatalf("empty env should fall back: got %q", got)
	}
}
