package io.github.shirainbown.sharelink.emailcode;

import java.net.URI;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
import reactor.core.publisher.Mono;
import io.github.shirainbown.sharelink.SharelinkSettingConfigGetter;

public interface EmailCodeManager {

    /**
     * Sends a verification code to the given email. Fails with
     * {@link SendRateLimitedException} when any rate limit is exceeded.
     *
     * @param email normalized email (lowercased and trimmed)
     * @param clientIp client ip for auxiliary rate limiting, may be null
     * @param config email verify config
     */
    Mono<Void> sendCode(String email, String clientIp,
                        SharelinkSettingConfigGetter.EmailVerifyConfig config);

    /**
     * Sends a verification code with an explicit notification reason type, so download
     * and protected-link verifications can use distinct email templates.
     */
    Mono<Void> sendCode(String email, String clientIp,
                        SharelinkSettingConfigGetter.EmailVerifyConfig config,
                        String reasonType);

    /**
     * Verifies the code for the given email. Each invocation accumulates attempts and the
     * code is invalidated once the max attempts is exceeded or the verification succeeds.
     */
    Mono<Boolean> verify(String email, String code,
                         SharelinkSettingConfigGetter.EmailVerifyConfig config);

    Mono<Void> invalidate(String email);

    class SendRateLimitedException extends ResponseStatusException {
        public static final String TYPE =
            "https://www.halo.run/probs/email-code-send-rate-limited";

        public SendRateLimitedException(Type type) {
            super(HttpStatus.TOO_MANY_REQUESTS, type.detail);
            setType(URI.create(TYPE));
        }

        public enum Type {
            RESEND_TOO_FREQUENT("验证码发送过于频繁，请稍后再试"),
            DAILY_LIMIT_EXCEEDED("今日验证码发送次数已达上限，请明天再试"),
            IP_HOURLY_LIMIT_EXCEEDED("当前网络环境验证码发送过于频繁，请稍后再试");

            private final String detail;

            Type(String detail) {
                this.detail = detail;
            }
        }
    }
}
