package services

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

type OTPlessRequest struct {
	Email string `json:"email"`
	OTP   string `json:"otp"`
}

func SendEmailOTP(email string, otp string) error {

	// systemflag first, environment second - the same order the SMS gateway
	// uses. The rows are named otplessClientId / otplessSecretKey, which is how
	// they were already spelled in the database.
	clientID := configValue(FlagOtplessClientID, "OTPLESS_CLIENT_ID", "")

	clientSecret := configValue(FlagOtplessClientSecret, "OTPLESS_CLIENT_SECRET", "")

	if clientID == "" || clientSecret == "" {
		return fmt.Errorf(
			"OTPLESS is not configured: set the %s and %s systemflag rows, or OTPLESS_CLIENT_ID and OTPLESS_CLIENT_SECRET",
			FlagOtplessClientID,
			FlagOtplessClientSecret,
		)
	}

	body := OTPlessRequest{
		Email: email,
		OTP:   otp,
	}

	jsonBody, _ := json.Marshal(body)

	req, err := http.NewRequest(
		"POST",
		"https://auth.otpless.app/auth/v1/initiate/email",
		bytes.NewBuffer(jsonBody),
	)

	if err != nil {
		return err
	}

	req.Header.Set(
		"clientId",
		clientID,
	)

	req.Header.Set(
		"clientSecret",
		clientSecret,
	)

	req.Header.Set(
		"Content-Type",
		"application/json",
	)

	client := &http.Client{
		Timeout: 15 * time.Second,
	}

	resp, err := client.Do(req)

	if err != nil {
		return err
	}

	defer resp.Body.Close()

	// The status used to be ignored and nil returned regardless, so a 401 from
	// a missing OTPLESS_CLIENT_ID read as a delivered mail and never reached
	// the caller's log line. Email delivery was unobservable, which is how
	// OTPLESS being absent from the committed .env went unnoticed.
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {

		body, _ := io.ReadAll(io.LimitReader(resp.Body, 2048))

		return fmt.Errorf(
			"OTPLESS HTTP %d: %s",
			resp.StatusCode,
			strings.TrimSpace(string(body)),
		)
	}

	return nil
}