package auth

import (
	"context"
	"strings"

	"gateway/internal/library/zitadel"
	authmetaenum "gateway/internal/model/auth/domain/enum"
	dommember "gateway/internal/model/member/domain/usecase"
	"gateway/internal/svc"
)

func federatedEmailAllowed(claims *zitadel.IDTokenClaims, provider string, trustSocial bool) error {
	if claims == nil {
		return errb.SvcThirdParty("empty id token claims")
	}
	if claims.EmailVerified || trustSocial {
		return nil
	}
	if strings.EqualFold(strings.TrimSpace(provider), "ldap") {
		return nil
	}
	return errb.AuthForbidden("social email is not verified")
}

// resolveMemberForFederatedLogin loads an existing member or provisions on first LDAP login.
func resolveMemberForFederatedLogin(
	ctx context.Context,
	sc *svc.ServiceContext,
	tenantID string,
	claims *zitadel.IDTokenClaims,
	provider string,
) (*dommember.MemberDTO, error) {
	if sc.MemberProfile == nil {
		return nil, errb.SysNotImplemented("member profile not configured")
	}
	member, err := sc.MemberProfile.GetByZitadelUserID(ctx, tenantID, claims.Sub)
	if err == nil {
		if err := ensureLoginEligible(member.Status); err != nil {
			return nil, err
		}
		return member, nil
	}
	if !isMemberNotFound(err) {
		return nil, err
	}

	provider = strings.ToLower(strings.TrimSpace(provider))
	if provider == "google" {
		return nil, errb.ResNotFound("account not found, please register first").WithCause(err)
	}
	if sc.MemberProvisioning == nil {
		return nil, err
	}

	switch provider {
	case "ldap":
		return sc.MemberProvisioning.EnsureFromLDAP(ctx, &dommember.EnsureFromLDAPRequest{
			TenantID:    tenantID,
			ZitadelSub:  claims.Sub,
			ExternalID:  claims.Sub,
			Email:       claims.Email,
			DisplayName: claims.Name,
		})
	default:
		return sc.MemberProvisioning.EnsureFromOIDC(ctx, &dommember.EnsureFromOIDCRequest{
			TenantID:      tenantID,
			ZitadelSub:    claims.Sub,
			Email:         claims.Email,
			EmailVerified: claims.EmailVerified,
			DisplayName:   claims.Name,
			Locale:        claims.Locale,
		})
	}
}

func registrationChannelForProvider(provider string) authmetaenum.RegistrationChannel {
	switch strings.ToLower(strings.TrimSpace(provider)) {
	case "ldap":
		return authmetaenum.RegistrationChannelLDAP
	default:
		return authmetaenum.RegistrationChannelGoogle
	}
}
