package migration

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"

	"golang.org/x/oauth2/google"
	"golang.org/x/oauth2/jwt"
)

var googleDWDScopes = []string{
	"https://www.googleapis.com/auth/gmail.readonly",
	"https://www.googleapis.com/auth/drive.readonly",
	"https://www.googleapis.com/auth/calendar.readonly",
	"https://www.googleapis.com/auth/contacts.readonly",
}

// GoogleDWD mints access tokens via a service account with domain-wide delegation.
type GoogleDWD struct {
	jwtConfig *jwt.Config
}

func NewGoogleDWD(jsonKey string) (*GoogleDWD, error) {
	jsonKey = strings.TrimSpace(jsonKey)
	if jsonKey == "" {
		return nil, nil
	}
	conf, err := google.JWTConfigFromJSON([]byte(jsonKey), googleDWDScopes...)
	if err != nil {
		return nil, fmt.Errorf("parse google service account: %w", err)
	}
	return &GoogleDWD{jwtConfig: conf}, nil
}

func (g *GoogleDWD) Enabled() bool {
	return g != nil && g.jwtConfig != nil
}

func (g *GoogleDWD) AccessToken(ctx context.Context, subjectEmail string) (string, error) {
	if !g.Enabled() {
		return "", fmt.Errorf("google domain-wide delegation not configured")
	}
	subjectEmail = strings.ToLower(strings.TrimSpace(subjectEmail))
	if subjectEmail == "" {
		return "", fmt.Errorf("subject email required for domain-wide delegation")
	}
	conf := *g.jwtConfig
	conf.Subject = subjectEmail
	token, err := conf.TokenSource(ctx).Token()
	if err != nil {
		return "", fmt.Errorf("google dwd token: %w", err)
	}
	if token.AccessToken == "" {
		return "", fmt.Errorf("google dwd token empty")
	}
	return token.AccessToken, nil
}

func validateServiceAccountJSON(raw string) error {
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return nil
	}
	var probe struct {
		ClientEmail string `json:"client_email"`
		PrivateKey  string `json:"private_key"`
	}
	if err := json.Unmarshal([]byte(raw), &probe); err != nil {
		return fmt.Errorf("invalid service account json: %w", err)
	}
	if probe.ClientEmail == "" || probe.PrivateKey == "" {
		return fmt.Errorf("service account json missing client_email or private_key")
	}
	return nil
}
