package v1

import (
	"context"
	"fmt"
	"os"

	"github.com/spf13/viper"
	"golang.org/x/oauth2/google"
	admin "google.golang.org/api/admin/directory/v1"
	"google.golang.org/api/gmail/v1"
	"google.golang.org/api/option"

	"github.com/pingcap-inc/security/pkg/log"
)

const (
	dwdGCPSA      = "google-ws-admin-sdk@gcp-digital-infra.iam.gserviceaccount.com"
	dwdGCPSubject = "liuy@pingcap.com"
	gcpTokenEP    = "https://oauth2.googleapis.com/token"
)

type googleService struct {
}

type GoogleServiceInterface interface {
	WsSrv(ctx context.Context, wsType string, scope ...string) (interface{}, error)
}

func NewGoogleService() GoogleServiceInterface {
	return &googleService{}
}

func (g *googleService) WsSrv(ctx context.Context, wsType string, scope ...string) (interface{}, error) {
	if len(scope) == 0 {
		return nil, fmt.Errorf("google: google client scope is required")
	}

	gcsServiceAccountFile := viper.GetString("ws-sa")
	_, err := os.Stat(gcsServiceAccountFile)
	if err != nil {
		log.L(ctx).Errorf("Failed to get file info: %v", err)

		return nil, err
	}

	serviceAccount, err := os.ReadFile(gcsServiceAccountFile)
	if err != nil {
		log.L(ctx).Errorf("Failed to read service account file: %v", err)
	}

	var adSrv interface{}
	switch wsType {
	case "admin":
		adSrv, err = g.newAdminSrv(ctx, dwdGCPSubject, serviceAccount, scope...)
	case "gmail":
		adSrv, err = g.newGmailSrv(ctx, dwdGCPSubject, serviceAccount, scope...)

	default:
		return nil, fmt.Errorf("google: google client scope is required")
	}
	if err != nil {
		log.L(ctx).Errorf("admin.NewService error: %v", err)

		return nil, err
	}

	return adSrv, nil
}

func (g *googleService) newAdminSrv(ctx context.Context, userEmail string, serviceAccount []byte, scope ...string) (*admin.Service, error) {
	if len(scope) == 0 {
		return nil, fmt.Errorf("google: google client scope is required")
	}

	config, err := google.JWTConfigFromJSON(serviceAccount, scope...)
	if err != nil {
		return nil, fmt.Errorf("google: error getting JWT config from Service Account: %v", err)
	}

	config.Subject = userEmail
	ts := config.TokenSource(ctx)
	svc, err := admin.NewService(ctx, option.WithTokenSource(ts))
	// svc, err := admin.NewGroupsSettingService(ctx, options.WithTokenSource(ts))
	if err != nil {
		return nil, fmt.Errorf("google: error creating service: %v", err)
	}

	return svc, nil
}
func (g *googleService) newGmailSrv(ctx context.Context, userEmail string, serviceAccount []byte, scope ...string) (*gmail.Service, error) {
	if len(scope) == 0 {
		return nil, fmt.Errorf("google: google client scope is required")
	}

	config, err := google.JWTConfigFromJSON(serviceAccount, scope...)
	if err != nil {
		return nil, fmt.Errorf("google: error getting JWT config from Service Account: %v", err)
	}

	config.Subject = userEmail
	ts := config.TokenSource(ctx)
	svc, err := gmail.NewService(ctx, option.WithTokenSource(ts))
	// svc, err := admin.NewGroupsSettingService(ctx, options.WithTokenSource(ts))
	if err != nil {
		return nil, fmt.Errorf("google: error creating service: %v", err)
	}

	return svc, nil
}
