"""
Copyright (c) 2020, VRAI Labs and/or its affiliates. All rights reserved.

This software is licensed under the Apache License, Version 2.0 (the
"License") as published by the Apache Software Foundation.

You may not use this file except in compliance with the License. You may
obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
"""
import asyncio
import json

from fastapi import FastAPI
from fastapi.requests import Request
from fastapi.testclient import TestClient
from pytest import fixture
from pytest import mark

from supertokens_python import init
from supertokens_python.recipe import session, emailpassword
from supertokens_python.recipe.emailverification.interfaces import APIInterface, APIOptions
from supertokens_python.exceptions import BadInputError
from supertokens_python.framework.fastapi import Middleware
from supertokens_python.querier import Querier
from supertokens_python.recipe.session import create_new_session, refresh_session, get_session
from tests.utils import (
    reset, setup_st, clean_st, start_st, sign_up_request, extract_all_cookies, email_verify_token_request,
    set_key_value_in_config, TEST_ACCESS_TOKEN_MAX_AGE_CONFIG_KEY
)


def setup_function(f):
    reset()
    clean_st()
    setup_st()


def teardown_function(f):
    reset()
    clean_st()


@fixture(scope='function')
async def driver_config_client():
    app = FastAPI()
    app.add_middleware(Middleware)

    @app.get('/login')
    async def login(request: Request):
        user_id = 'userId'
        await create_new_session(request, user_id, {}, {})
        return {'userId': user_id}

    @app.post('/refresh')
    async def custom_refresh(request: Request):
        await refresh_session(request)
        return {}

    @app.get('/info')
    async def info_get(request: Request):
        await get_session(request, True)
        return {}

    @app.get('/custom/info')
    def custom_info(_):
        return {}

    @app.options('/custom/handle')
    def custom_handle_options(_):
        return {'method': 'option'}

    @app.get('/handle')
    async def handle_get(request: Request):
        session = await get_session(request, True)
        return {'s': session.get_handle()}

    @app.post('/logout')
    async def custom_logout(request: Request):
        session = await get_session(request, True)
        await session.revoke_session()
        return {}

    return TestClient(app)


@mark.asyncio
async def test_the_generate_token_api_with_valid_input_email_not_verified(driver_config_client: TestClient):
    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init({})
        ],
    })
    start_st()

    response_1 = sign_up_request(
        driver_config_client,
        "test@gmail.com",
        "testPass123")

    assert response_1.status_code == 200
    dict_response = json.loads(response_1.text)
    assert dict_response["status"] == "OK"

    user_id = dict_response["user"]["id"]
    cookies = extract_all_cookies(response_1)

    response = email_verify_token_request(driver_config_client, cookies['sAccessToken']['value'],
                                          cookies['sIdRefreshToken']['value'], response_1.headers.get(
                                              'anti-csrf'),
                                          user_id)
    dict_response = json.loads(response.text)
    assert dict_response["status"] == "OK"


@mark.asyncio
async def test_the_generate_token_api_with_valid_input_email_verified_and_test_error(driver_config_client: TestClient):
    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init({})
        ],
    })
    start_st()

    response_1 = sign_up_request(
        driver_config_client,
        "test@gmail.com",
        "testPass123")

    assert response_1.status_code == 200
    dict_response = json.loads(response_1.text)
    assert dict_response["status"] == "OK"

    user_id = dict_response["user"]["id"]
    cookies = extract_all_cookies(response_1)

    verify_token = await emailpassword.create_email_verification_token(user_id)
    await emailpassword.verify_email_using_token(verify_token.token)

    response = email_verify_token_request(driver_config_client, cookies['sAccessToken']['value'],
                                          cookies['sIdRefreshToken']['value'], response_1.headers.get(
                                              'anti-csrf'),
                                          user_id)
    dict_response = json.loads(response.text)
    assert dict_response["status"] == "EMAIL_ALREADY_VERIFIED_ERROR"


@mark.asyncio
async def test_the_generate_token_api_with_valid_input_no_session_and_check_output(driver_config_client: TestClient):
    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init({})
        ],
    })
    start_st()

    response_1 = driver_config_client.post(url='/auth/user/email/verify/token')
    assert response_1.status_code == 401
    dict_response = json.loads(response_1.text)
    assert dict_response["message"] == "unauthorised"


@mark.asyncio
async def test_the_generate_token_api_with_an_expired_access_token_and_see_that_try_refresh_token_is_returned(
        driver_config_client: TestClient):
    set_key_value_in_config(
        TEST_ACCESS_TOKEN_MAX_AGE_CONFIG_KEY,
        2)

    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init({})
        ],
    })
    start_st()

    response_1 = sign_up_request(
        driver_config_client,
        "test@gmail.com",
        "testPass123")
    assert response_1.status_code == 200
    dict_response = json.loads(response_1.text)
    assert dict_response["status"] == "OK"
    user_id = dict_response["user"]["id"]

    cookies = extract_all_cookies(response_1)

    await asyncio.sleep(5)

    response_2 = email_verify_token_request(driver_config_client, cookies['sAccessToken']['value'],
                                            cookies['sIdRefreshToken']['value'], response_1.headers.get(
                                                'anti-csrf'),
                                            user_id)
    dict_response = json.loads(response_2.text)

    assert response_2.status_code == 401
    assert dict_response['message'] == 'try refresh token'

    response_3 = driver_config_client.post(
        url="/auth/session/refresh",
        headers={
            "Content-Type": "application/json",
            'anti-csrf': response_1.headers.get('anti-csrf')
        },
        cookies={
            'sRefreshToken': cookies['sRefreshToken']['value'],
            'sIdRefreshToken': cookies['sIdRefreshToken']['value'],
        })

    assert response_3.status_code == 200

    cookies1 = extract_all_cookies(response_3)
    response_4 = email_verify_token_request(driver_config_client, cookies1['sAccessToken']['value'],
                                            cookies1['sIdRefreshToken']['value'], response_3.headers.get(
                                                'anti-csrf'),
                                            user_id)

    dict_response = json.loads(response_4.text)

    assert response_4.status_code == 200
    assert dict_response['status'] == 'OK'


@mark.asyncio
async def test_that_providing_your_own_email_callback_and_make_sure_it_is_called(driver_config_client: TestClient):
    user_info = None
    email_token = None

    def custom_f(user, email_verification_url_token):
        nonlocal user_info, email_token
        user_info = user
        email_token = email_verification_url_token

    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init({
                'email_verification_feature': {
                    'create_and_send_custom_email': custom_f
                }
            })
        ],
    })
    start_st()

    response_1 = sign_up_request(
        driver_config_client,
        "test@gmail.com",
        "testPass123")
    await asyncio.sleep(1)
    assert response_1.status_code == 200
    dict_response = json.loads(response_1.text)
    assert dict_response["status"] == "OK"
    user_id = dict_response["user"]["id"]

    cookies = extract_all_cookies(response_1)

    response_2 = email_verify_token_request(driver_config_client, cookies['sAccessToken']['value'],
                                            cookies['sIdRefreshToken']['value'], response_1.headers.get(
                                                'anti-csrf'),
                                            user_id)
    await asyncio.sleep(2)

    dict_response = json.loads(response_2.text)
    assert dict_response['status'] == 'OK'

    assert user_info.user_id == user_id
    assert user_info.email == "test@gmail.com"
    assert email_token is not None


@mark.asyncio
async def test_the_email_verify_API_with_valid_input(driver_config_client: TestClient):
    token = None

    async def custom_f(user, email_verification_url_token):
        nonlocal token
        token = email_verification_url_token.split(
            "?token=")[1].split("&ride")[0]

    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init({
                'email_verification_feature': {
                    'create_and_send_custom_email': custom_f
                }
            })
        ],
    })
    start_st()

    response_1 = sign_up_request(
        driver_config_client,
        "test@gmail.com",
        "testPass123")
    await asyncio.sleep(1)
    assert response_1.status_code == 200
    dict_response = json.loads(response_1.text)
    assert dict_response["status"] == "OK"
    user_id = dict_response["user"]["id"]

    cookies = extract_all_cookies(response_1)

    response_2 = email_verify_token_request(driver_config_client, cookies['sAccessToken']['value'],
                                            cookies['sIdRefreshToken']['value'], response_1.headers.get(
                                                'anti-csrf'),
                                            user_id)
    await asyncio.sleep(2)

    dict_response = json.loads(response_2.text)
    assert dict_response['status'] == 'OK'

    assert token is not None

    response_3 = driver_config_client.post(
        url="/auth/user/email/verify",
        headers={
            "Content-Type": "application/json",
            'anti-csrf': response_1.headers.get('anti-csrf')
        },
        cookies={
            'sRefreshToken': cookies['sRefreshToken']['value'],
            'sIdRefreshToken': cookies['sIdRefreshToken']['value'],
        },
        json={
            "method": "token",
            "token": token
        }
    )

    dict_response = json.loads(response_3.text)
    assert dict_response['status'] == 'OK'


@mark.asyncio
async def test_the_email_verify_API_with_invalid_token_and_check_error(driver_config_client: TestClient):
    token = None

    async def custom_f(user, email_verification_url_token):
        nonlocal token
        token = email_verification_url_token.split(
            "?token=")[1].split("&ride")[0]

    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init({
                'email_verification_feature': {
                    'create_and_send_custom_email': custom_f
                }
            })
        ],
    })
    start_st()

    response_1 = sign_up_request(
        driver_config_client,
        "test@gmail.com",
        "testPass123")
    await asyncio.sleep(1)
    assert response_1.status_code == 200
    dict_response = json.loads(response_1.text)
    assert dict_response["status"] == "OK"
    user_id = dict_response["user"]["id"]

    cookies = extract_all_cookies(response_1)

    response_2 = email_verify_token_request(driver_config_client, cookies['sAccessToken']['value'],
                                            cookies['sIdRefreshToken']['value'], response_1.headers.get(
                                                'anti-csrf'),
                                            user_id)
    await asyncio.sleep(2)

    dict_response = json.loads(response_2.text)
    assert dict_response['status'] == 'OK'

    assert token is not None

    response_3 = driver_config_client.post(
        url="/auth/user/email/verify",
        headers={
            "Content-Type": "application/json",
            'anti-csrf': response_1.headers.get('anti-csrf')
        },
        cookies={
            'sRefreshToken': cookies['sRefreshToken']['value'],
            'sIdRefreshToken': cookies['sIdRefreshToken']['value'],
        },
        json={
            "method": "token",
            "token": "bad token"
        }
    )

    dict_response = json.loads(response_3.text)
    assert dict_response['status'] == 'EMAIL_VERIFICATION_INVALID_TOKEN_ERROR'


@mark.asyncio
async def test_the_email_verify_API_with_token_of_not_type_string(driver_config_client: TestClient):
    token = None

    async def custom_f(user, email_verification_url_token):
        nonlocal token
        token = email_verification_url_token.split(
            "?token=")[1].split("&ride")[0]

    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init({
                'email_verification_feature': {
                    'create_and_send_custom_email': custom_f
                }
            })
        ],
    })
    start_st()

    response_1 = sign_up_request(
        driver_config_client,
        "test@gmail.com",
        "testPass123")
    await asyncio.sleep(1)
    assert response_1.status_code == 200
    dict_response = json.loads(response_1.text)
    assert dict_response["status"] == "OK"
    user_id = dict_response["user"]["id"]

    cookies = extract_all_cookies(response_1)

    response_2 = email_verify_token_request(driver_config_client, cookies['sAccessToken']['value'],
                                            cookies['sIdRefreshToken']['value'], response_1.headers.get(
                                                'anti-csrf'),
                                            user_id)
    await asyncio.sleep(2)

    dict_response = json.loads(response_2.text)
    assert dict_response['status'] == 'OK'

    assert token is not None

    response_3 = driver_config_client.post(
        url="/auth/user/email/verify",
        headers={
            "Content-Type": "application/json",
            'anti-csrf': response_1.headers.get('anti-csrf')
        },
        cookies={
            'sRefreshToken': cookies['sRefreshToken']['value'],
            'sIdRefreshToken': cookies['sIdRefreshToken']['value'],
        },
        json={
            "method": "token",
            "token": 200
        }
    )

    dict_response = json.loads(response_3.text)
    assert response_3.status_code == 400
    assert dict_response['message'] == 'The email verification token must be a string'


@mark.asyncio
async def test_that_the_handlePostEmailVerification_callback_is_called_on_successfull_verification_if_given(
        driver_config_client: TestClient):
    token = None
    user_info_from_callback = None

    async def custom_f(user, email_verification_url_token):
        nonlocal token
        token = email_verification_url_token.split(
            "?token=")[1].split("&ride")[0]

    def apis_override_email_password(param: APIInterface):
        temp = param.email_verify_post

        async def email_verify_post(token: str, api_options: APIOptions):
            nonlocal user_info_from_callback

            response = await temp(token, api_options)

            if response.status == "OK":
                user_info_from_callback = response.user

            return response

        param.email_verify_post = email_verify_post
        return param

    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init({
                'email_verification_feature': {
                    'create_and_send_custom_email': custom_f
                },
                'override': {
                    'email_verification_feature':
                        {
                            'apis': apis_override_email_password
                        }
                }
            })
        ],
    })
    start_st()

    response_1 = sign_up_request(
        driver_config_client,
        "test@gmail.com",
        "testPass123")
    await asyncio.sleep(1)
    assert response_1.status_code == 200
    dict_response = json.loads(response_1.text)
    assert dict_response["status"] == "OK"
    user_id = dict_response["user"]["id"]

    cookies = extract_all_cookies(response_1)

    response_2 = email_verify_token_request(driver_config_client, cookies['sAccessToken']['value'],
                                            cookies['sIdRefreshToken']['value'], response_1.headers.get(
                                                'anti-csrf'),
                                            user_id)
    await asyncio.sleep(2)

    dict_response = json.loads(response_2.text)
    assert dict_response['status'] == 'OK'

    assert token is not None

    response_3 = driver_config_client.post(
        url="/auth/user/email/verify",
        headers={
            "Content-Type": "application/json",
            'anti-csrf': response_1.headers.get('anti-csrf')
        },
        cookies={
            'sRefreshToken': cookies['sRefreshToken']['value'],
            'sIdRefreshToken': cookies['sIdRefreshToken']['value'],
        },
        json={
            "method": "token",
            "token": token
        }
    )

    dict_response = json.loads(response_3.text)
    assert response_3.status_code == 200
    assert dict_response['status'] == 'OK'

    await asyncio.sleep(1)

    assert user_info_from_callback.user_id == user_id
    assert user_info_from_callback.email == "test@gmail.com"


@mark.asyncio
async def test_the_email_verify_with_valid_input_using_the_get_method(driver_config_client: TestClient):
    token = None

    async def custom_f(user, email_verification_url_token):
        nonlocal token
        token = email_verification_url_token.split(
            "?token=")[1].split("&ride")[0]

    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init({
                'email_verification_feature': {
                    'create_and_send_custom_email': custom_f
                }
            })
        ],
    })
    start_st()

    response_1 = sign_up_request(
        driver_config_client,
        "test@gmail.com",
        "testPass123")
    await asyncio.sleep(1)
    assert response_1.status_code == 200
    dict_response = json.loads(response_1.text)
    assert dict_response["status"] == "OK"
    user_id = dict_response["user"]["id"]

    cookies = extract_all_cookies(response_1)

    response_2 = email_verify_token_request(driver_config_client, cookies['sAccessToken']['value'],
                                            cookies['sIdRefreshToken']['value'], response_1.headers.get(
                                                'anti-csrf'),
                                            user_id)
    await asyncio.sleep(2)

    dict_response = json.loads(response_2.text)
    assert dict_response['status'] == 'OK'

    assert token is not None

    response_3 = driver_config_client.post(
        url="/auth/user/email/verify",
        json={
            "method": "token",
            "token": token
        }
    )

    dict_response = json.loads(response_3.text)
    assert response_3.status_code == 200
    assert dict_response['status'] == "OK"

    response_4 = driver_config_client.get(
        url="/auth/user/email/verify",
        headers={
            "Content-Type": "application/json",
            'anti-csrf': response_1.headers.get('anti-csrf')
        },
        cookies={
            'sAccessToken': cookies['sAccessToken']['value'],
            'sIdRefreshToken': cookies['sIdRefreshToken']['value'],
        })

    dict_response = json.loads(response_4.text)
    assert response_4.status_code == 200
    assert dict_response['status'] == 'OK'


@mark.asyncio
async def test_the_email_verify_with_no_session_using_the_get_method(driver_config_client: TestClient):
    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init()
        ],
    })
    start_st()

    response_4 = driver_config_client.get(url="/auth/user/email/verify")

    dict_response = json.loads(response_4.text)
    assert response_4.status_code == 401
    assert dict_response['message'] == 'unauthorised'


@mark.asyncio
async def test_the_email_verify_API_with_valid_input_overriding_apis(driver_config_client: TestClient):
    token = None
    user_info_from_callback = None

    async def custom_f(user, email_verification_url_token):
        nonlocal token
        token = email_verification_url_token.split(
            "?token=")[1].split("&ride")[0]

    def apis_override_email_password(param: APIInterface):
        temp = param.email_verify_post

        async def email_verify_post(token: str, api_options: APIOptions):
            nonlocal user_info_from_callback

            response = await temp(token, api_options)

            if response.status == "OK":
                user_info_from_callback = response.user

            return response

        param.email_verify_post = email_verify_post
        return param

    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init({
                'email_verification_feature': {
                    'create_and_send_custom_email': custom_f
                },
                'override': {
                    'email_verification_feature':
                        {
                            'apis': apis_override_email_password
                        }
                }
            })
        ],
    })
    start_st()

    response_1 = sign_up_request(
        driver_config_client,
        "test@gmail.com",
        "testPass123")
    await asyncio.sleep(1)
    assert response_1.status_code == 200
    dict_response = json.loads(response_1.text)
    assert dict_response["status"] == "OK"
    user_id = dict_response["user"]["id"]

    cookies = extract_all_cookies(response_1)

    response_2 = email_verify_token_request(driver_config_client, cookies['sAccessToken']['value'],
                                            cookies['sIdRefreshToken']['value'], response_1.headers.get(
                                                'anti-csrf'),
                                            user_id)
    await asyncio.sleep(2)

    dict_response = json.loads(response_2.text)
    assert dict_response['status'] == 'OK'

    assert token is not None

    response_3 = driver_config_client.post(
        url="/auth/user/email/verify",
        json={
            "method": "token",
            "token": token
        }
    )

    dict_response = json.loads(response_3.text)
    assert response_3.status_code == 200
    assert dict_response['status'] == 'OK'

    await asyncio.sleep(1)

    assert user_info_from_callback.user_id == user_id
    assert user_info_from_callback.email == "test@gmail.com"


@mark.asyncio
async def test_the_email_verify_API_with_valid_input_overriding_apis_throws_error(driver_config_client: TestClient):
    token = None
    user_info_from_callback = None

    async def custom_f(user, email_verification_url_token):
        nonlocal token
        token = email_verification_url_token.split(
            "?token=")[1].split("&ride")[0]

    def apis_override_email_password(param: APIInterface):
        temp = param.email_verify_post

        async def email_verify_post(token: str, api_options: APIOptions):
            nonlocal user_info_from_callback

            response = await temp(token, api_options)

            if response.status == "OK":
                user_info_from_callback = response.user

            raise BadInputError("verify exception")

        param.email_verify_post = email_verify_post
        return param

    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init({
                'email_verification_feature': {
                    'create_and_send_custom_email': custom_f
                },
                'override': {
                    'email_verification_feature':
                        {
                            'apis': apis_override_email_password
                        }
                }
            })
        ],
    })
    start_st()

    response_1 = sign_up_request(
        driver_config_client,
        "test@gmail.com",
        "testPass123")
    await asyncio.sleep(1)
    assert response_1.status_code == 200
    dict_response = json.loads(response_1.text)
    assert dict_response["status"] == "OK"
    user_id = dict_response["user"]["id"]

    cookies = extract_all_cookies(response_1)

    response_2 = email_verify_token_request(driver_config_client, cookies['sAccessToken']['value'],
                                            cookies['sIdRefreshToken']['value'], response_1.headers.get(
                                                'anti-csrf'),
                                            user_id)
    await asyncio.sleep(2)

    dict_response = json.loads(response_2.text)
    assert dict_response['status'] == 'OK'

    assert token is not None

    response_3 = driver_config_client.post(
        url="/auth/user/email/verify",
        json={
            "method": "token",
            "token": token
        }
    )

    dict_response = json.loads(response_3.text)
    assert response_3.status_code == 400
    assert dict_response['message'] == 'verify exception'

    await asyncio.sleep(1)

    assert user_info_from_callback.user_id == user_id
    assert user_info_from_callback.email == "test@gmail.com"


@mark.asyncio
async def test_the_generate_token_api_with_valid_input_and_then_remove_token(driver_config_client: TestClient):
    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init()
        ],
    })
    start_st()

    version = await Querier.get_instance().get_api_version()
    assert version == "2.9"

    response_1 = sign_up_request(
        driver_config_client,
        "test@gmail.com",
        "testPass123")
    assert response_1.status_code == 200
    dict_response = json.loads(response_1.text)
    assert dict_response["status"] == "OK"
    user_id = dict_response["user"]["id"]

    verify_token = await emailpassword.create_email_verification_token(user_id)
    await emailpassword.revoke_email_verification_token(user_id)

    response = await emailpassword.verify_email_using_token(verify_token.token)
    assert response.status == "EMAIL_VERIFICATION_INVALID_TOKEN_ERROR"


@mark.asyncio
async def test_the_generate_token_api_with_valid_input_verify_and_then_unverify_email(driver_config_client: TestClient):
    init({
        'supertokens': {
            'connection_uri': "http://localhost:3567",
        },
        'framework': 'fastapi',
        'app_info': {
            'app_name': "SuperTokens Demo",
            'api_domain': "http://api.supertokens.io",
            'website_domain': "supertokens.io",
            'api_base_path': "/auth"
        },
        'recipe_list': [session.init(
            {
                'anti_csrf': 'VIA_TOKEN'
            }
        ),
            emailpassword.init()
        ],
    })
    start_st()

    version = await Querier.get_instance().get_api_version()
    assert version == "2.9"

    response_1 = sign_up_request(
        driver_config_client,
        "test@gmail.com",
        "testPass123")
    assert response_1.status_code == 200
    dict_response = json.loads(response_1.text)
    assert dict_response["status"] == "OK"
    user_id = dict_response["user"]["id"]

    verify_token = await emailpassword.create_email_verification_token(user_id)
    await emailpassword.verify_email_using_token(verify_token.token)

    assert (await emailpassword.is_email_verified(user_id))

    await emailpassword.unverify_email(user_id)

    is_verified = await emailpassword.is_email_verified(user_id)
    assert is_verified is False
