// Package dbaas defines the data model for Database-as-a-Service provider
// configurations managed through the dashboard.
package dbaas

import (
	"fmt"
	"log"
	"strings"

	"go.yaml.in/yaml/v3"

	"github.com/tidbcloud/AgentTeam/desktop/internal/crypto"
)

// Known DBaaS provider types.
const (
	ProviderTiDBCloud = "tidb_cloud"
	ProviderTEM       = "tem"
	ProviderPingCAP   = "pingcap_cloud"
)

// AllProviders contains the supported DBaaS providers.
var AllProviders = []string{
	ProviderTiDBCloud,
	ProviderTEM,
	ProviderPingCAP,
}

// Service defines a dashboard-managed DBaaS provider configuration.
type Service struct {
	// ID is the unique identifier for the service entry.
	ID string `yaml:"id" json:"id"`
	// Name is the human-readable display name.
	Name string `yaml:"name,omitempty" json:"name,omitempty"`
	// Provider is the DBaaS provider type (tidb_cloud, tem, pingcap_cloud).
	Provider string `yaml:"provider" json:"provider"`
	// APIKey stores the provider credential.
	APIKey string `yaml:"api_key,omitempty" json:"api_key,omitempty"`
}

type serviceAlias Service

func (s Service) MarshalYAML() (interface{}, error) {
	alias := serviceAlias(s)

	if alias.APIKey != "" && crypto.KeysSet() {
		encrypted, err := crypto.Encrypt(alias.APIKey)
		if err != nil {
			log.Printf("dbaas: encrypt api key for %q: %v", s.ID, err)
			return alias, nil
		}
		alias.APIKey = encrypted
	}

	return alias, nil
}

func (s *Service) UnmarshalYAML(value *yaml.Node) error {
	var alias serviceAlias
	if err := value.Decode(&alias); err != nil {
		return err
	}
	*s = Service(alias)
	return s.decryptAPIKey()
}

func (s *Service) decryptAPIKey() error {
	if s.APIKey != "" && crypto.KeysSet() && crypto.IsEncrypted(s.APIKey) {
		decrypted, err := crypto.Decrypt(s.APIKey)
		if err != nil {
			log.Printf("dbaas: decrypt api key for %q: %v", s.ID, err)
			return err
		}
		s.APIKey = decrypted
	}
	return nil
}

// Validate checks a service for correctness.
func Validate(s Service) error {
	var errs []string

	if strings.TrimSpace(s.ID) == "" {
		errs = append(errs, "service ID must not be empty")
	}

	providerValid := false
	for _, p := range AllProviders {
		if s.Provider == p {
			providerValid = true
			break
		}
	}
	if !providerValid {
		errs = append(errs, fmt.Sprintf("unsupported provider %q", s.Provider))
	}

	if len(errs) > 0 {
		return fmt.Errorf("validation failed: %s", strings.Join(errs, "; "))
	}

	return nil
}

// Normalize trims whitespace on fields.
func Normalize(s Service) Service {
	s.ID = strings.TrimSpace(s.ID)
	s.Name = strings.TrimSpace(s.Name)
	s.Provider = strings.TrimSpace(s.Provider)
	s.APIKey = strings.TrimSpace(s.APIKey)
	return s
}
