import * as better_call from 'better-call';
import * as better_auth from 'better-auth';
import { User } from 'better-auth';
import { APIError } from 'better-auth/api';
import { BetterAuthPlugin } from 'better-auth/types';
import normalizeEmail from 'validator/lib/normalizeEmail.js';
import { Matcher } from './email/matchers.js';

interface UserWithNormalizedEmail extends User {
    normalizedEmail?: string | null;
}
interface EmailHarmonySchema {
    user: {
        fields: {
            /** Map the normalizedEmail field name to a custom value */
            normalizedEmail?: string;
        };
    };
}
interface EmailHarmonyOptions {
    /**
     * Allow logging in with any version of the unnormalized email address. Also works for password
     * reset. For example a user who signed up with the email `johndoe@googlemail.com` may also log
     * in with `john.doe@gmail.com`. Makes 1 extra database query for every login attempt.
     * @default false
     */
    allowNormalizedSignin?: boolean;
    /**
     * Function to validate email. Default is `validateEmail`.
     */
    validator?: (email: string) => boolean | Promise<boolean>;
    /**
     * Function to normalize email address. Default is `validator.normalizeEmail(t)`.
     * @see https://github.com/validatorjs/validator.js#sanitizers
     */
    normalizer?: typeof normalizeEmail;
    /**
     * Specify in which routes the plugin should run, for example by path.
     * @example <caption>Ready-made matchers</caption>
     * import * as matchers from 'better-auth-harmony/email/matchers';
     *
     * export const auth = betterAuth({
     *   // ... other config options
     *   plugins: [
     *     emailHarmony({
     *       matchers: {
     *         signIn: [matchers.emailOtpVerify, matchers.emailOtpForget, matchers.emailOtpReset]
     *       }
     *     })
     *   ]
     * });
     */
    matchers?: {
        /**
         * Specify where the plugin should run to look up users by normalized email address if
         * `allowNormalizedSignin` is true.
         * @default [`allEmailSignIn`]
         */
        signIn?: Matcher[];
        /**
         * Specify which requests the plugin should validate, for example in which routes by path.
         * @default [`allEmail`]
         */
        validation?: Matcher[];
    };
    /** Pass the `schema` option to customize the field names */
    schema?: EmailHarmonySchema;
}
/**
 * The default validation function runs `validator.isEmail(email) && Mailchecker.isValid(email)`.
 * @see https://github.com/validatorjs/validator.js#validators
 * @see https://github.com/FGRibreau/mailchecker
 * @param email The email address to validate
 * @returns Boolean indicating whether the address should be accepted (`true`), or rejected
 *   (`false`).
 */
declare const validateEmail: (email: string) => boolean;
declare const emailHarmony: ({ allowNormalizedSignin, validator, matchers, schema, normalizer }?: EmailHarmonyOptions) => {
    id: "harmony-email";
    init(): {
        options: {
            databaseHooks: {
                user: {
                    create: {
                        before: (user: Partial<User> & {
                            phoneNumber?: string;
                        }) => Promise<false | {
                            data: Required<User>;
                        } | {
                            data: {
                                normalizedEmail: string;
                                id: string;
                                createdAt: Date;
                                updatedAt: Date;
                                email: string;
                                emailVerified: boolean;
                                name: string;
                                image: string | null;
                            };
                        }>;
                    };
                    update: {
                        before: (user: Partial<User> & {
                            phoneNumber?: string;
                        }) => Promise<false | {
                            data: Required<User>;
                        } | {
                            data: {
                                normalizedEmail: string;
                                id: string;
                                createdAt: Date;
                                updatedAt: Date;
                                email: string;
                                emailVerified: boolean;
                                name: string;
                                image: string | null;
                            };
                        }>;
                    };
                };
            };
        };
    };
    schema: {
        user: {
            fields: {
                normalizedEmail: {
                    type: "string";
                    fieldName: string;
                    required: false;
                    unique: true;
                    input: false;
                    returned: false;
                };
            };
        };
    };
    hooks: {
        before: ({
            matcher: (context: better_auth.HookEndpointContext) => boolean;
            handler: (inputContext: better_call.MiddlewareInputContext<better_call.MiddlewareOptions>) => Promise<void>;
        } | {
            matcher: (context: better_auth.HookEndpointContext) => boolean;
            handler: (inputContext: better_call.MiddlewareInputContext<better_call.MiddlewareOptions>) => Promise<{
                context: {
                    query: {
                        email: string;
                        normalizedEmail: string;
                    };
                    method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
                    path: string;
                    body: any;
                    params: Record<string, any> & string;
                    request: Request | undefined;
                    headers: Headers | undefined;
                    setHeader: ((key: string, value: string) => void) & ((key: string, value: string) => void);
                    setStatus: (status: better_call.Status) => void;
                    getHeader: ((key: string) => string | null) & ((key: string) => string | null);
                    getCookie: (key: string, prefix?: better_call.CookiePrefixOptions) => string | null;
                    getSignedCookie: (key: string, secret: string, prefix?: better_call.CookiePrefixOptions) => Promise<string | null | false>;
                    setCookie: (key: string, value: string, options?: better_call.CookieOptions) => string;
                    setSignedCookie: (key: string, value: string, secret: string, options?: better_call.CookieOptions) => Promise<string>;
                    json: (<R extends Record<string, any> | null>(json: R, routerResponse?: {
                        status?: number;
                        headers?: Record<string, string>;
                        response?: Response;
                        body?: Record<string, string>;
                    } | Response) => Promise<R>) & (<R extends Record<string, any> | null>(json: R, routerResponse?: {
                        status?: number;
                        headers?: Record<string, string>;
                        response?: Response;
                    } | Response) => Promise<R>);
                    context: {
                        [x: string]: any;
                    } & {
                        returned?: unknown | undefined;
                        responseHeaders?: Headers | undefined;
                        getPlugin: <Plugin extends BetterAuthPlugin>(pluginId: Plugin["id"]) => Plugin | null;
                        appName: string;
                        baseURL: string;
                        version: string;
                        options: better_auth.BetterAuthOptions;
                        trustedOrigins: string[];
                        isTrustedOrigin: (url: string, settings?: {
                            allowRelativePaths: boolean;
                        }) => boolean;
                        oauthConfig: {
                            skipStateCookieCheck?: boolean | undefined;
                            storeStateStrategy: "database" | "cookie";
                        };
                        newSession: {
                            session: better_auth.Session & Record<string, any>;
                            user: User & Record<string, any>;
                        } | null;
                        session: {
                            session: better_auth.Session & Record<string, any>;
                            user: User & Record<string, any>;
                        } | null;
                        setNewSession: (session: {
                            session: better_auth.Session & Record<string, any>;
                            user: User & Record<string, any>;
                        } | null) => void;
                        socialProviders: better_auth.OAuthProvider[];
                        authCookies: better_auth.BetterAuthCookies;
                        logger: ReturnType<(options?: better_auth.Logger | undefined) => better_auth.InternalLogger>;
                        rateLimit: {
                            enabled: boolean;
                            window: number;
                            max: number;
                            storage: "memory" | "database" | "secondary-storage";
                        } & Omit<better_auth.BetterAuthRateLimitOptions, "enabled" | "window" | "max" | "storage">;
                        adapter: better_auth.DBAdapter<better_auth.BetterAuthOptions>;
                        internalAdapter: better_auth.InternalAdapter<better_auth.BetterAuthOptions>;
                        createAuthCookie: (cookieName: string, overrideAttributes?: Partial<better_call.CookieOptions> | undefined) => better_auth.BetterAuthCookie;
                        secret: string;
                        sessionConfig: {
                            updateAge: number;
                            expiresIn: number;
                            freshAge: number;
                            cookieRefreshCache: false | {
                                enabled: true;
                                updateAge: number;
                            };
                        };
                        generateId: (options: {
                            model: better_auth.ModelNames;
                            size?: number | undefined;
                        }) => string | false;
                        secondaryStorage: better_auth.SecondaryStorage | undefined;
                        password: {
                            hash: (password: string) => Promise<string>;
                            verify: (data: {
                                password: string;
                                hash: string;
                            }) => Promise<boolean>;
                            config: {
                                minPasswordLength: number;
                                maxPasswordLength: number;
                            };
                            checkPassword: (userId: string, ctx: better_auth.GenericEndpointContext<better_auth.BetterAuthOptions>) => Promise<boolean>;
                        };
                        tables: better_auth.BetterAuthDBSchema;
                        runMigrations: () => Promise<void>;
                        publishTelemetry: (event: {
                            type: string;
                            anonymousId?: string | undefined;
                            payload: Record<string, any>;
                        }) => Promise<void>;
                        skipOriginCheck: boolean | string[];
                        skipCSRFCheck: boolean;
                        runInBackground: (promise: Promise<unknown>) => void;
                        runInBackgroundOrAwait: (promise: Promise<unknown> | void) => better_auth.Awaitable<unknown>;
                    };
                    redirect: (url: string) => APIError;
                    error: (status: ("OK" | "CREATED" | "ACCEPTED" | "NO_CONTENT" | "MULTIPLE_CHOICES" | "MOVED_PERMANENTLY" | "FOUND" | "SEE_OTHER" | "NOT_MODIFIED" | "TEMPORARY_REDIRECT" | "BAD_REQUEST" | "UNAUTHORIZED" | "PAYMENT_REQUIRED" | "FORBIDDEN" | "NOT_FOUND" | "METHOD_NOT_ALLOWED" | "NOT_ACCEPTABLE" | "PROXY_AUTHENTICATION_REQUIRED" | "REQUEST_TIMEOUT" | "CONFLICT" | "GONE" | "LENGTH_REQUIRED" | "PRECONDITION_FAILED" | "PAYLOAD_TOO_LARGE" | "URI_TOO_LONG" | "UNSUPPORTED_MEDIA_TYPE" | "RANGE_NOT_SATISFIABLE" | "EXPECTATION_FAILED" | "I'M_A_TEAPOT" | "MISDIRECTED_REQUEST" | "UNPROCESSABLE_ENTITY" | "LOCKED" | "FAILED_DEPENDENCY" | "TOO_EARLY" | "UPGRADE_REQUIRED" | "PRECONDITION_REQUIRED" | "TOO_MANY_REQUESTS" | "REQUEST_HEADER_FIELDS_TOO_LARGE" | "UNAVAILABLE_FOR_LEGAL_REASONS" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "BAD_GATEWAY" | "SERVICE_UNAVAILABLE" | "GATEWAY_TIMEOUT" | "HTTP_VERSION_NOT_SUPPORTED" | "VARIANT_ALSO_NEGOTIATES" | "INSUFFICIENT_STORAGE" | "LOOP_DETECTED" | "NOT_EXTENDED" | "NETWORK_AUTHENTICATION_REQUIRED") | better_call.Status, body?: {
                        message?: string;
                        code?: string;
                    } & Record<string, any>, headers?: HeadersInit) => APIError;
                };
            } | {
                context: {
                    body: {
                        email: string;
                        normalizedEmail: string;
                    };
                    method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
                    path: string;
                    query: Record<string, any> | undefined;
                    params: Record<string, any> & string;
                    request: Request | undefined;
                    headers: Headers | undefined;
                    setHeader: ((key: string, value: string) => void) & ((key: string, value: string) => void);
                    setStatus: (status: better_call.Status) => void;
                    getHeader: ((key: string) => string | null) & ((key: string) => string | null);
                    getCookie: (key: string, prefix?: better_call.CookiePrefixOptions) => string | null;
                    getSignedCookie: (key: string, secret: string, prefix?: better_call.CookiePrefixOptions) => Promise<string | null | false>;
                    setCookie: (key: string, value: string, options?: better_call.CookieOptions) => string;
                    setSignedCookie: (key: string, value: string, secret: string, options?: better_call.CookieOptions) => Promise<string>;
                    json: (<R extends Record<string, any> | null>(json: R, routerResponse?: {
                        status?: number;
                        headers?: Record<string, string>;
                        response?: Response;
                        body?: Record<string, string>;
                    } | Response) => Promise<R>) & (<R extends Record<string, any> | null>(json: R, routerResponse?: {
                        status?: number;
                        headers?: Record<string, string>;
                        response?: Response;
                    } | Response) => Promise<R>);
                    context: {
                        [x: string]: any;
                    } & {
                        returned?: unknown | undefined;
                        responseHeaders?: Headers | undefined;
                        getPlugin: <Plugin extends BetterAuthPlugin>(pluginId: Plugin["id"]) => Plugin | null;
                        appName: string;
                        baseURL: string;
                        version: string;
                        options: better_auth.BetterAuthOptions;
                        trustedOrigins: string[];
                        isTrustedOrigin: (url: string, settings?: {
                            allowRelativePaths: boolean;
                        }) => boolean;
                        oauthConfig: {
                            skipStateCookieCheck?: boolean | undefined;
                            storeStateStrategy: "database" | "cookie";
                        };
                        newSession: {
                            session: better_auth.Session & Record<string, any>;
                            user: User & Record<string, any>;
                        } | null;
                        session: {
                            session: better_auth.Session & Record<string, any>;
                            user: User & Record<string, any>;
                        } | null;
                        setNewSession: (session: {
                            session: better_auth.Session & Record<string, any>;
                            user: User & Record<string, any>;
                        } | null) => void;
                        socialProviders: better_auth.OAuthProvider[];
                        authCookies: better_auth.BetterAuthCookies;
                        logger: ReturnType<(options?: better_auth.Logger | undefined) => better_auth.InternalLogger>;
                        rateLimit: {
                            enabled: boolean;
                            window: number;
                            max: number;
                            storage: "memory" | "database" | "secondary-storage";
                        } & Omit<better_auth.BetterAuthRateLimitOptions, "enabled" | "window" | "max" | "storage">;
                        adapter: better_auth.DBAdapter<better_auth.BetterAuthOptions>;
                        internalAdapter: better_auth.InternalAdapter<better_auth.BetterAuthOptions>;
                        createAuthCookie: (cookieName: string, overrideAttributes?: Partial<better_call.CookieOptions> | undefined) => better_auth.BetterAuthCookie;
                        secret: string;
                        sessionConfig: {
                            updateAge: number;
                            expiresIn: number;
                            freshAge: number;
                            cookieRefreshCache: false | {
                                enabled: true;
                                updateAge: number;
                            };
                        };
                        generateId: (options: {
                            model: better_auth.ModelNames;
                            size?: number | undefined;
                        }) => string | false;
                        secondaryStorage: better_auth.SecondaryStorage | undefined;
                        password: {
                            hash: (password: string) => Promise<string>;
                            verify: (data: {
                                password: string;
                                hash: string;
                            }) => Promise<boolean>;
                            config: {
                                minPasswordLength: number;
                                maxPasswordLength: number;
                            };
                            checkPassword: (userId: string, ctx: better_auth.GenericEndpointContext<better_auth.BetterAuthOptions>) => Promise<boolean>;
                        };
                        tables: better_auth.BetterAuthDBSchema;
                        runMigrations: () => Promise<void>;
                        publishTelemetry: (event: {
                            type: string;
                            anonymousId?: string | undefined;
                            payload: Record<string, any>;
                        }) => Promise<void>;
                        skipOriginCheck: boolean | string[];
                        skipCSRFCheck: boolean;
                        runInBackground: (promise: Promise<unknown>) => void;
                        runInBackgroundOrAwait: (promise: Promise<unknown> | void) => better_auth.Awaitable<unknown>;
                    };
                    redirect: (url: string) => APIError;
                    error: (status: ("OK" | "CREATED" | "ACCEPTED" | "NO_CONTENT" | "MULTIPLE_CHOICES" | "MOVED_PERMANENTLY" | "FOUND" | "SEE_OTHER" | "NOT_MODIFIED" | "TEMPORARY_REDIRECT" | "BAD_REQUEST" | "UNAUTHORIZED" | "PAYMENT_REQUIRED" | "FORBIDDEN" | "NOT_FOUND" | "METHOD_NOT_ALLOWED" | "NOT_ACCEPTABLE" | "PROXY_AUTHENTICATION_REQUIRED" | "REQUEST_TIMEOUT" | "CONFLICT" | "GONE" | "LENGTH_REQUIRED" | "PRECONDITION_FAILED" | "PAYLOAD_TOO_LARGE" | "URI_TOO_LONG" | "UNSUPPORTED_MEDIA_TYPE" | "RANGE_NOT_SATISFIABLE" | "EXPECTATION_FAILED" | "I'M_A_TEAPOT" | "MISDIRECTED_REQUEST" | "UNPROCESSABLE_ENTITY" | "LOCKED" | "FAILED_DEPENDENCY" | "TOO_EARLY" | "UPGRADE_REQUIRED" | "PRECONDITION_REQUIRED" | "TOO_MANY_REQUESTS" | "REQUEST_HEADER_FIELDS_TOO_LARGE" | "UNAVAILABLE_FOR_LEGAL_REASONS" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "BAD_GATEWAY" | "SERVICE_UNAVAILABLE" | "GATEWAY_TIMEOUT" | "HTTP_VERSION_NOT_SUPPORTED" | "VARIANT_ALSO_NEGOTIATES" | "INSUFFICIENT_STORAGE" | "LOOP_DETECTED" | "NOT_EXTENDED" | "NETWORK_AUTHENTICATION_REQUIRED") | better_call.Status, body?: {
                        message?: string;
                        code?: string;
                    } & Record<string, any>, headers?: HeadersInit) => APIError;
                };
            } | undefined>;
        })[];
    };
};

export { type EmailHarmonyOptions, type EmailHarmonySchema, type UserWithNormalizedEmail, emailHarmony as default, validateEmail };
