package member

import (
	"context"
	"strings"

	memberenum "gateway/internal/model/member/domain/enum"
	domusecase "gateway/internal/model/member/domain/usecase"
	"gateway/internal/svc"
	"gateway/internal/types"
)

func ensurePlatformNativePassword(member *domusecase.MemberDTO) error {
	if member == nil {
		return errb.ResNotFound("member", "")
	}
	switch member.Origin {
	case memberenum.MemberOriginPlatformNative:
		return nil
	case memberenum.MemberOriginOIDC:
		return errb.AuthForbidden("social login accounts cannot change password here")
	case memberenum.MemberOriginLDAP:
		return errb.AuthForbidden("ldap accounts cannot change password here")
	case memberenum.MemberOriginSCIM:
		return errb.AuthForbidden("scim provisioned accounts cannot change password here")
	default:
		return errb.AuthForbidden("account cannot change password here")
	}
}

// totpEnrolledForActor uses TOTP status (authoritative) with profile flag as fallback.
func totpEnrolledForActor(
	ctx context.Context,
	sc *svc.ServiceContext,
	tenantID, uid string,
	member *domusecase.MemberDTO,
) (bool, error) {
	if sc.MemberTOTP != nil {
		status, err := sc.MemberTOTP.Status(ctx, tenantID, uid)
		if err != nil {
			return false, err
		}
		if status != nil {
			return status.Enrolled, nil
		}
	}
	if member != nil {
		return member.TOTPEnrolled, nil
	}
	return false, nil
}

// ensurePasswordChangeStepUp requires TOTP enrollment and a consumed step-up token
// or inline TOTP code before password change.
func ensurePasswordChangeStepUp(
	ctx context.Context,
	sc *svc.ServiceContext,
	tenantID, uid string,
	member *domusecase.MemberDTO,
	req *types.ChangePasswordReq,
) error {
	if sc.MemberTOTP == nil {
		return errb.SysNotImplemented("member TOTP not configured")
	}
	enrolled, err := totpEnrolledForActor(ctx, sc, tenantID, uid, member)
	if err != nil {
		return err
	}
	if !enrolled {
		return errb.AuthForbidden("enroll totp before changing password")
	}

	token := strings.TrimSpace(req.StepUpToken)
	code := strings.TrimSpace(req.TOTPCode)
	if token == "" && code == "" {
		return errb.AuthForbidden("totp verification required before password change")
	}
	if token != "" && code != "" {
		return errb.InputInvalidFormat("provide either step_up_token or totp_code, not both")
	}

	if code != "" {
		return sc.MemberTOTP.VerifyCode(ctx, tenantID, uid, code)
	}

	if err := requireStepUp(sc); err != nil {
		return err
	}
	return sc.MemberStepUp.Consume(ctx, &domusecase.ConsumeStepUpRequest{
		TokenID:  token,
		TenantID: tenantID,
		UID:      uid,
		Purpose:  memberenum.StepUpPurposeChangePassword,
	})
}
