package authn

import (
	"strings"

	"github.com/photoprism/photoprism/pkg/clean"
	"github.com/photoprism/photoprism/pkg/txt"
)

// MethodType represents an authentication method.
type MethodType string

// Authentication methods.
const (
	MethodUndefined MethodType = ""
	MethodDefault   MethodType = "default"
	MethodSession   MethodType = "session"
	MethodOAuth2    MethodType = "oauth2"
	Method2FA       MethodType = "2fa"
	MethodJWT       MethodType = "jwt"
)

// Method casts a string to a normalized method type.
func Method(s string) MethodType {
	s = clean.TypeLowerUnderscore(s)
	switch s {
	case "":
		return MethodUndefined
	case "_", "-", "null", "nil", "0", "false":
		return MethodDefault
	case "oauth2", "oauth":
		return MethodOAuth2
	case "2fa", "mfa", "otp", "totp":
		return Method2FA
	case "jwt", "jwks":
		return MethodJWT
	case "access_token":
		return MethodDefault
	default:
		return MethodType(s)
	}
}

// Methods casts a string to normalized method type strings.
func Methods(s string) []MethodType {
	items := strings.Split(s, ",")
	result := make([]MethodType, 0, len(items))

	for i := range items {
		result = append(result, Method(items[i]))
	}

	return result
}

// Pretty returns the provider identifier in an easy-to-read format.
func (t MethodType) Pretty() string {
	switch t {
	case MethodOAuth2:
		return "OAuth2"
	case Method2FA:
		return "2FA"
	case MethodJWT:
		return "JWT"
	default:
		return txt.UpperFirst(t.String())
	}
}

// String returns the provider identifier as a string.
func (t MethodType) String() string {
	switch t {
	case "", "access_token":
		return string(MethodDefault)
	case "oauth":
		return string(MethodOAuth2)
	case "2fa", "otp", "totp":
		return string(Method2FA)
	default:
		return string(t)
	}
}

// Equal checks if the type matches the specified string.
func (t MethodType) Equal(s string) bool {
	return strings.EqualFold(s, t.String())
}

// NotEqual checks if the type does not match the specified string.
func (t MethodType) NotEqual(s string) bool {
	return !t.Equal(s)
}

// Is compares the method with another type.
func (t MethodType) Is(methodType MethodType) bool {
	return t == methodType
}

// IsNot checks if the method is not the specified type.
func (t MethodType) IsNot(methodType MethodType) bool {
	return t != methodType
}

// IsUndefined checks if the method is undefined.
func (t MethodType) IsUndefined() bool {
	return t == ""
}

// IsDefault checks if this is the default method.
func (t MethodType) IsDefault() bool {
	return t.String() == MethodDefault.String()
}

// IsSession checks if this is the session method.
func (t MethodType) IsSession() bool {
	return t.String() == MethodSession.String()
}

// IsJWT checks if this is the JSON Web Token (JWT) method.
func (t MethodType) IsJWT() bool {
	return t.String() == MethodJWT.String()
}
