package user

import (
	"Yimaru-Backend/internal/domain"
	"context"
	"crypto/subtle"
	"errors"
	"time"
)

func (s *Service) SendResetCode(ctx context.Context, medium domain.OtpMedium, sentTo string, provider domain.SMSProvider) error {
	var user domain.User
	var err error

	// Look up user by email or phone to get the actual userID
	switch medium {
	case domain.OtpMediumEmail:
		user, err = s.userStore.GetUserByEmailPhone(ctx, sentTo, "")
	case domain.OtpMediumSms:
		user, err = s.userStore.GetUserByEmailPhone(ctx, "", sentTo)
	default:
		return errors.New("invalid OTP medium")
	}

	if err != nil {
		return err
	}

	// Use the actual user ID when storing OTP
	return s.SendOtp(ctx, user.ID, sentTo, domain.OtpReset, medium, provider)
}

func (s *Service) ResetPassword(ctx context.Context, resetReq domain.ResetPasswordReq) error {
	// Look up user by email or phone (don't trust client-provided user_id)
	var user domain.User
	var err error

	if resetReq.Email != "" {
		user, err = s.userStore.GetUserByEmailPhone(ctx, resetReq.Email, "")
	} else if resetReq.PhoneNumber != "" {
		user, err = s.userStore.GetUserByEmailPhone(ctx, "", resetReq.PhoneNumber)
	} else {
		return errors.New("email or phone number is required")
	}

	if err != nil {
		return err
	}

	// Get OTP for the actual user
	otp, err := s.otpStore.GetOtp(ctx, user.ID)
	if err != nil {
		return err
	}

	// Validate OTP purpose (should be for reset, not registration)
	if otp.For != domain.OtpReset {
		return domain.ErrInvalidOtp
	}

	if otp.Used {
		return domain.ErrOtpAlreadyUsed
	}

	if time.Now().After(otp.ExpiresAt) {
		return domain.ErrOtpExpired
	}

	// Use constant-time comparison for OTP
	if subtle.ConstantTimeCompare([]byte(otp.Otp), []byte(resetReq.OtpCode)) != 1 {
		return domain.ErrInvalidOtp
	}

	// Hash the new password before storing
	hashedPassword, err := hashPassword(resetReq.Password)
	if err != nil {
		return err
	}

	// Update password with hashed value
	err = s.userStore.UpdatePasswordHash(ctx, hashedPassword, user.ID)
	if err != nil {
		return err
	}

	// Mark OTP as used to prevent replay attacks
	err = s.otpStore.MarkOtpAsUsed(ctx, otp)
	if err != nil {
		return err
	}

	return nil
}
