package benefactorservice

import (
	"context"
	"math/rand"
	"time"

	benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactor"
	errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
	richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
)

func (s Service) SendOtp(ctx context.Context, req benefactoreparam.SendOtpRequest) (benefactoreparam.SendOtpResponse, error) {
	const op = "benefactorservice.SendOtp"
	if fieldErrors, vErr := s.vld.ValidateSendOtpRequest(ctx, req); vErr != nil {
		return benefactoreparam.SendOtpResponse{FieldErrors: fieldErrors}, richerror.New(op).WithErr(vErr)
	}

	isExist, iErr := s.redisOtp.IsExistPhoneNumber(ctx, req.PhoneNumber)
	if iErr != nil {
		return benefactoreparam.SendOtpResponse{}, richerror.New(op).WithErr(iErr).WithKind(richerror.KindUnexpected)
	}
	if isExist {
		return benefactoreparam.SendOtpResponse{}, richerror.New(op).WithMessage(errmsg.ErrorMsgOtpCodeExist).WithKind(richerror.KindForbidden)
	}

	newCode := s.generateVerificationCode()
	spErr := s.redisOtp.SaveCodeWithPhoneNumber(ctx, req.PhoneNumber, newCode, s.config.OtpExpireTime)
	if spErr != nil {
		return benefactoreparam.SendOtpResponse{}, richerror.New(op).WithErr(spErr).WithKind(richerror.KindUnexpected)
	}

	go s.smsAdapter.Send(req.PhoneNumber, newCode)

	// we use code in sendOtpResponse until sms provider will implement
	return benefactoreparam.SendOtpResponse{
		PhoneNumber: req.PhoneNumber,
		Code:        newCode, // TODO - have to remove it in production
	}, nil
}

func (s Service) generateVerificationCode() string {
	rand.NewSource(time.Now().UnixNano())
	result := make([]byte, s.config.LengthOfOtpCode)
	for i := 0; i < s.config.LengthOfOtpCode; i++ {
		//nolint
		result[i] = s.config.OtpChars[rand.Intn(len(s.config.OtpChars))]
	}

	return string(result)
}
