package repository

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"time"

	redislib "gateway/internal/library/redis"
	authdomain "gateway/internal/model/auth/domain"
	domrepo "gateway/internal/model/auth/domain/repository"

	"github.com/zeromicro/go-zero/core/stores/redis"
)

type redisLoginMFAChallengeStore struct {
	client *redis.Redis
}

// NewRedisLoginMFAChallengeStore creates a Redis-backed login MFA challenge store.
func NewRedisLoginMFAChallengeStore(client *redislib.Client) domrepo.LoginMFAChallengeStore {
	if client == nil || client.Zero() == nil {
		panic("auth: redis client is required for login mfa challenge store")
	}
	return &redisLoginMFAChallengeStore{client: client.Zero()}
}

func (s *redisLoginMFAChallengeStore) Save(ctx context.Context, challenge *domrepo.LoginMFAChallenge, ttl time.Duration) error {
	if challenge == nil || challenge.ChallengeID == "" {
		return fmt.Errorf("auth: login mfa challenge id is required")
	}
	raw, err := json.Marshal(challenge)
	if err != nil {
		return fmt.Errorf("auth: marshal login mfa challenge: %w", err)
	}
	seconds := int(ttl.Seconds())
	if seconds < 1 {
		seconds = 1
	}
	return s.client.SetexCtx(ctx, authdomain.LoginMFAChallengeRedisKey(challenge.ChallengeID), string(raw), seconds)
}

func (s *redisLoginMFAChallengeStore) Get(ctx context.Context, challengeID string) (*domrepo.LoginMFAChallenge, error) {
	val, err := s.client.GetCtx(ctx, authdomain.LoginMFAChallengeRedisKey(challengeID))
	if errors.Is(err, redis.Nil) {
		return nil, authdomain.ErrLoginMFAChallengeNotFound
	}
	if err != nil {
		return nil, err
	}
	var challenge domrepo.LoginMFAChallenge
	if err := json.Unmarshal([]byte(val), &challenge); err != nil {
		return nil, fmt.Errorf("auth: unmarshal login mfa challenge: %w", err)
	}
	return &challenge, nil
}

func (s *redisLoginMFAChallengeStore) Delete(ctx context.Context, challengeID string) error {
	_, err := s.client.DelCtx(ctx, authdomain.LoginMFAChallengeRedisKey(challengeID))
	return err
}

var _ domrepo.LoginMFAChallengeStore = (*redisLoginMFAChallengeStore)(nil)
