package providers

import (
	"context"
	"errors"
	"testing"

	"github.com/wangjia/pangolin/server/internal/provision"
)

func TestRegistry_UnknownKind(t *testing.T) {
	r := NewRegistry()
	_, err := r.For(&provision.Provider{APIKind: "does-not-exist"})
	if err == nil {
		t.Fatal("expected error for unknown api_kind")
	}
}

func TestRegistry_NoCredentials(t *testing.T) {
	// Ensure the env vars are unset for a clean assertion.
	t.Setenv("PROVISION_VULTR_API_KEY", "")
	t.Setenv("PROVISION_HETZNER_API_TOKEN", "")

	r := NewRegistry()
	if _, err := r.For(&provision.Provider{APIKind: "vultr"}); !errors.Is(err, provision.ErrNoCredentials) {
		t.Errorf("vultr without creds: err = %v, want ErrNoCredentials", err)
	}
	if _, err := r.For(&provision.Provider{APIKind: "hetzner"}); !errors.Is(err, provision.ErrNoCredentials) {
		t.Errorf("hetzner without creds: err = %v, want ErrNoCredentials", err)
	}
}

func TestRegistry_RegisterAndCache(t *testing.T) {
	r := NewRegistry()
	built := 0
	r.Register("fake", func() (provision.CloudAdapter, error) {
		built++
		return stubAdapter{}, nil
	})
	p := &provision.Provider{APIKind: "fake"}
	if _, err := r.For(p); err != nil {
		t.Fatalf("For: %v", err)
	}
	if _, err := r.For(p); err != nil {
		t.Fatalf("For (cached): %v", err)
	}
	if built != 1 {
		t.Errorf("factory built %d times, want 1 (cached)", built)
	}
}

func TestRegistry_CredentialsFromEnv(t *testing.T) {
	t.Setenv("PROVISION_VULTR_API_KEY", "secret-key")
	r := NewRegistry()
	a, err := r.For(&provision.Provider{APIKind: "vultr"})
	if err != nil {
		t.Fatalf("vultr with creds: %v", err)
	}
	if a.Kind() != "vultr" {
		t.Errorf("kind = %s, want vultr", a.Kind())
	}
	if !a.SupportsElasticIP() {
		t.Error("vultr should support elastic IP (reserved IPs)")
	}
}

type stubAdapter struct{}

func (stubAdapter) Kind() string            { return "fake" }
func (stubAdapter) SupportsElasticIP() bool { return false }
func (stubAdapter) CreateInstance(context.Context, provision.CreateInput) (*provision.Instance, error) {
	return &provision.Instance{ID: "x"}, nil
}
func (stubAdapter) DestroyInstance(context.Context, string) error           { return nil }
func (stubAdapter) AttachIP(context.Context, string) (string, error)        { return "", nil }
func (stubAdapter) ListRegions(context.Context) ([]provision.Region, error) { return nil, nil }
