package cloud_provider

import (
	"os"
	"path/filepath"

	"github.com/juju/errors"
	"github.com/tidbcloud/auto-deploy/internal/types"
	"github.com/tidbcloud/auto-deploy/internal/utils"
)

type gcpCloudProvider struct {
	oidcProvider types.OidcProvider
	region       string
	account      types.Account
}

func NewGCPCloudProvider(oidcProvider types.OidcProvider, region string, account types.Account) (types.CloudProvider, error) {
	// try to get id token
	_, err := oidcProvider.GetIdToken()
	if err != nil {
		return nil, err
	}
	return &gcpCloudProvider{
		oidcProvider: oidcProvider,
		region:       region,
		account:      account,
	}, nil
}

func (a *gcpCloudProvider) GetCloudProviderType() types.CloudProviderType {
	return types.GCP
}

func (a *gcpCloudProvider) GetAuthConfigPath(homeDir string) string {
	return homeDir + "/.config/gcloud"
}

func (a *gcpCloudProvider) GetAuthConfigSubPath() []string {
	return []string{"application_default_credentials.json", "configurations/config_default"}
}

func (a *gcpCloudProvider) GetAuthConfigYaml(name string, accounts []types.Account) string {
	return `
apiVersion: v1
kind: Secret
type: Opaque
metadata:
    name: ` + name + `
stringData:
    application_default_credentials.json: |
` + utils.GetContentWithIndent(8, a.getDefaultCredentials()) + `
    configurations/config_default: |
` + utils.GetContentWithIndent(8, a.getDefaultConfig())
}

func (a *gcpCloudProvider) getDefaultConfig() string {
	return `
[core]
project = ` + a.account.GcpProject + `
`
}

func (a *gcpCloudProvider) getDefaultCredentials() string {
	return `{
	"type": "external_account",
	"audience": "//iam.googleapis.com/` + a.account.WorkdloadIdentityProvider + `",
	"subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
	"token_url": "https://sts.googleapis.com/v1/token",
	"service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/` + a.account.ServiceAccount + `:generateAccessToken",
	"credential_source": {
		"url": "` + a.oidcProvider.GetTokenUrl() + `",
		"headers": {
			"Authorization": "Bearer ` + a.oidcProvider.GetToken() + `"
		},
		"format": {
			"type": "json",
			"subject_token_field_name": "value"
		}
	}
}`
}

func (a *gcpCloudProvider) WriteToLocal(homeDir string, accounts []types.Account) error {
	// do noting for fake provider
	if a.oidcProvider.IsFake() {
		return nil
	}

	path := a.GetAuthConfigPath(homeDir)
	err := os.MkdirAll(path, os.ModePerm&0o777)
	if err != nil {
		return errors.Annotatef(err, "Failed to create config path `%s`", path)
	}
	credPath := filepath.Join(path, "application_default_credentials.json")
	err = os.WriteFile(credPath, []byte(a.getDefaultCredentials()), os.ModePerm&0o644)
	if err != nil {
		return errors.Annotatef(err, "Failed to write credentials `%s`", credPath)
	}
	configDir := filepath.Join(path, "configurations")
	err = os.MkdirAll(configDir, os.ModePerm&0o644)
	if err != nil {
		return errors.Annotatef(err, "Failed to create configrations folder `%s`", configDir)
	}

	configPath := filepath.Join(configDir, "configurations")
	err = os.WriteFile(configPath, []byte(a.getDefaultConfig()), os.ModePerm&0o644)
	if err != nil {
		return errors.Annotatef(err, "Failed to write credentials `%s`", credPath)
	}
	return nil
}

func (a *gcpCloudProvider) CreateK8s(k8s *types.K8s) error {
	return errors.NotImplemented
}
func (a *gcpCloudProvider) DestroyK8s(k8s *types.K8s) error {
	return errors.NotImplemented
}
func (a *gcpCloudProvider) GetKubeConfig(k8s *types.K8s) (string, error) {
	return "", errors.NotImplemented
}
