package providers

import (
	"context"
	"encoding/base64"
	"os"

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

// vultrAdapter implements provision.CloudAdapter against the Vultr API v2.
// Consumable pool: cheap, hourly-billed, reserved-IP capable.
//
// Credentials: PROVISION_VULTR_API_KEY (env, independent secret).
// Default OS image: PROVISION_VULTR_OS_ID (defaults to a current Debian image).
type vultrAdapter struct {
	c    *httpClient
	osID int
}

func newVultrFromEnv() (provision.CloudAdapter, error) {
	key, err := secret("PROVISION_VULTR_API_KEY")
	if err != nil {
		return nil, err
	}
	osID := atoiDefault(os.Getenv("PROVISION_VULTR_OS_ID"), 2136) // 2136 = Debian 12 x64
	return &vultrAdapter{
		c:    newHTTPClient("https://api.vultr.com/v2", key),
		osID: osID,
	}, nil
}

func (a *vultrAdapter) Kind() string            { return "vultr" }
func (a *vultrAdapter) SupportsElasticIP() bool { return true } // reserved IPs

func (a *vultrAdapter) CreateInstance(ctx context.Context, in provision.CreateInput) (*provision.Instance, error) {
	body := map[string]any{
		"region":    in.Region,
		"plan":      in.Plan,
		"os_id":     a.osID,
		"label":     in.Label,
		"hostname":  in.Label,
		"user_data": base64.StdEncoding.EncodeToString([]byte(in.UserData)),
		"tags":      in.Tags,
		"backups":   "disabled",
	}
	if len(in.SSHKeyIDs) > 0 {
		body["sshkey_id"] = in.SSHKeyIDs
	}
	var resp struct {
		Instance struct {
			ID     string `json:"id"`
			MainIP string `json:"main_ip"`
			Region string `json:"region"`
		} `json:"instance"`
	}
	if err := a.c.do(ctx, "POST", "/instances", body, &resp); err != nil {
		return nil, err
	}
	return &provision.Instance{
		ID:     resp.Instance.ID,
		IP:     resp.Instance.MainIP,
		Region: resp.Instance.Region,
	}, nil
}

func (a *vultrAdapter) DestroyInstance(ctx context.Context, instanceID string) error {
	err := a.c.do(ctx, "DELETE", "/instances/"+instanceID, nil, nil)
	if err != nil && isNotFound(err) {
		return nil // idempotent: already gone
	}
	return err
}

func (a *vultrAdapter) AttachIP(ctx context.Context, instanceID string) (string, error) {
	// Allocate a reserved IPv4, then attach it to the instance.
	var created struct {
		ReservedIP struct {
			ID     string `json:"id"`
			Subnet string `json:"subnet"`
		} `json:"reserved_ip"`
	}
	if err := a.c.do(ctx, "POST", "/reserved-ips", map[string]any{
		"region":      "",
		"ip_type":     "v4",
		"label":       "rotate-" + instanceID,
		"instance_id": instanceID,
	}, &created); err != nil {
		return "", err
	}
	return created.ReservedIP.Subnet, nil
}

func (a *vultrAdapter) ListRegions(ctx context.Context) ([]provision.Region, error) {
	var resp struct {
		Regions []struct {
			ID      string `json:"id"`
			Country string `json:"country"`
			City    string `json:"city"`
		} `json:"regions"`
	}
	if err := a.c.do(ctx, "GET", "/regions", nil, &resp); err != nil {
		return nil, err
	}
	out := make([]provision.Region, 0, len(resp.Regions))
	for _, r := range resp.Regions {
		out = append(out, provision.Region{ID: r.ID, Country: r.Country, City: r.City})
	}
	return out, nil
}
