package handler

import (
	"context"

	"github.com/gin-gonic/gin"
	"github.com/pingcap/errors"
)

const (
	AWSAccountProvider      = "aws_account_provider"
	GCPAccountProvider      = "gcp_account_provider"
	AliCloudAccountProvider = "alicloud_account_provider"
	AzureAccountProvider    = "azure_account_provider"
)

type AccountHandler interface {
	GetAccountProvider(accountProvider string) (AccountProvider, error)
	GetAllAccountProviders() ([]AccountProvider, error)
}

var globalAccountHandler AccountHandler

func init() {
	globalAccountHandler = &AccountHandlerImpl{}
}

func SetAccountHandler(accountHandler AccountHandler) {
	// Unittest Only
	globalAccountHandler = accountHandler
}

func GetAccountHandler() AccountHandler {
	return globalAccountHandler
}

type AccountProvider interface {
	ResolveToken(token *string) (*string, error)
	ApproveCode(code *string) error
	GetTokenFromRedirect(c *gin.Context) (*string, error)
	GetFreeTrialFromRedirect(c *gin.Context) (bool, error)
	ProcessTenantSubscribeChange(ctx context.Context, processor ProcessTenantSubscribeChangeFunc) error
}

type AccountHandlerImpl struct {
}

const (
	SubscribeStatusSubscribed      = "subscribed"
	SubscribeStatusUnsubscribed    = "unsubscribed"
	SubscribeStatusSubscribeFailed = "subscribeFailed"
)

type SubscribeChange struct {
	AccountProvider string
	AccountCode     string
	SubscribeStatus string
	FreeTrial       bool
}

func (*AccountHandlerImpl) GetAccountProvider(accountProvider string) (AccountProvider, error) {
	if accountProvider == AWSAccountProvider {
		return &awsAccountProviderImpl{}, nil
	}
	if accountProvider == GCPAccountProvider {
		return &gcpAccountProviderImpl{}, nil
	}
	if accountProvider == AliCloudAccountProvider {
		return &aliyunAccountProviderImpl{}, nil
	}
	if accountProvider == AzureAccountProvider {
		return &azureAccountProviderImpl{}, nil
	}
	return nil, errors.New("invalid third party account provider")
}

func (*AccountHandlerImpl) GetAllAccountProviders() ([]AccountProvider, error) {
	return []AccountProvider{
		&awsAccountProviderImpl{},
		&gcpAccountProviderImpl{},
		&aliyunAccountProviderImpl{},
		&azureAccountProviderImpl{},
	}, nil
}

type ProcessTenantSubscribeChangeFunc func(context.Context, SubscribeChange) (bool, error)
