package auth

import (
	"fmt"
	"strings"

	"gitea.hostxtra.co.uk/mrhid6/vantage/server/internal/models"
)

// Preset describes one well-known identity provider.
//
// This is a Go table rather than a collection on purpose: adding a preset is a
// commit and a review, not a row somebody typed into production.
type Preset struct {
	ID            string   `json:"id"`
	Label         string   `json:"label"`          // shown in the add-provider picker
	Kind          string   `json:"kind"`           // models.KindOIDC | models.KindOAuth2
	IssuerFormat  string   `json:"-"`              // %s is replaced by InputValue; empty means no issuer
	InputLabel    string   `json:"input_label"`    // empty means the preset asks for nothing
	InputHint     string   `json:"input_hint"`
	Scopes        []string `json:"-"`
}

var presets = []Preset{
	{
		ID:           "entra",
		Label:        "Microsoft Entra ID",
		Kind:         models.KindOIDC,
		IssuerFormat: "https://login.microsoftonline.com/%s/v2.0",
		InputLabel:   "Directory (tenant) ID",
		InputHint:    "Found in Entra under Overview. A UUID, not your domain name.",
		Scopes:       []string{"openid", "profile", "email"},
	},
	{
		ID:           "google",
		Label:        "Google Workspace",
		Kind:         models.KindOIDC,
		IssuerFormat: "https://accounts.google.com",
		Scopes:       []string{"openid", "profile", "email"},
	},
	{
		ID:           "okta",
		Label:        "Okta",
		Kind:         models.KindOIDC,
		IssuerFormat: "https://%s/oauth2/default",
		InputLabel:   "Okta org domain",
		InputHint:    "e.g. acme.okta.com — no scheme, no trailing slash.",
		Scopes:       []string{"openid", "profile", "email"},
	},
	{
		ID:     "github",
		Label:  "GitHub",
		Kind:   models.KindOAuth2,
		Scopes: []string{"read:user", "user:email"},
	},
	{
		ID:           "",
		Label:        "Other (OpenID Connect)",
		Kind:         models.KindOIDC,
		IssuerFormat: "%s",
		InputLabel:   "Issuer URL",
		InputHint:    "The discovery base, e.g. https://id.example.com/realms/main",
		Scopes:       []string{"openid", "profile", "email"},
	},
}

// Presets returns the table for the settings UI to render a picker from.
func Presets() []Preset {
	out := make([]Preset, len(presets))
	copy(out, presets)
	return out
}

func PresetByID(id string) (Preset, bool) {
	for _, p := range presets {
		if p.ID == id {
			return p, true
		}
	}
	return Preset{}, false
}

// ExpandIssuer turns what the customer typed into the issuer URL that gets
// stored. The stored value is always fully resolved, so nothing downstream has
// to know a preset was involved.
func ExpandIssuer(presetID, input string) (string, error) {
	p, ok := PresetByID(presetID)
	if !ok {
		return "", fmt.Errorf("unknown provider preset %q", presetID)
	}
	if p.IssuerFormat == "" {
		return "", nil // OAuth2 providers have no issuer
	}
	if !strings.Contains(p.IssuerFormat, "%s") {
		return p.IssuerFormat, nil // fixed issuer, input ignored
	}
	input = strings.TrimSpace(strings.TrimSuffix(input, "/"))
	if input == "" {
		return "", fmt.Errorf("%s is required", p.InputLabel)
	}
	return fmt.Sprintf(p.IssuerFormat, input), nil
}

func DefaultScopes(presetID string) []string {
	p, ok := PresetByID(presetID)
	if !ok {
		return []string{"openid", "profile", "email"}
	}
	out := make([]string, len(p.Scopes))
	copy(out, p.Scopes)
	return out
}

func KindFor(presetID string) string {
	if p, ok := PresetByID(presetID); ok {
		return p.Kind
	}
	return models.KindOIDC
}
