from unittest.mock import patch
from uuid import uuid4

from flask_jwt_extended import create_access_token, create_refresh_token

from app.persistence.model import JwtModel, UserModel
from core.domains.authentication.dto.auth_dto import GetBlacklistDto, GetVerificationDto
from core.domains.authentication.repository.auth_repository import (
    AuthenticationRepository,
)
from core.domains.authentication.use_case.v1.auth_use_case import (
    LogoutUseCase,
    VerificationJWTUseCase,
)
from core.domains.user.entity.user_entity import UserEntity
from core.domains.user.repository.user_repository import UserRepository
from core.domains.user.use_case.v1.user_use_case import CreateUserUseCase
from core.use_case_output import UseCaseSuccessOutput, FailureType
from tests.app.http.requests.v1.test_auth_request import create_invalid_access_token
from tests.seeder.factory import make_custom_jwt

uuid = str(uuid4())


def test_logout_when_get_token_with_user_id_then_success(
    session, create_user,
):
    """
        given : access_token, user_id
        when : logout request
        then : success
    """
    user_id = create_user.id
    token = create_access_token(identity=user_id)
    token_to_byte = token.encode("utf-8")

    dto = GetBlacklistDto(user_id=user_id, access_token=token_to_byte)
    result = LogoutUseCase().execute(dto=dto)

    assert result.type == "success"
    assert isinstance(result, UseCaseSuccessOutput)
    assert b"blacklist_token" in result.value.data
    assert b"expired_at" in result.value.data


def test_verification_when_get_token_with_wrong_type_then_response_error(
    session, create_user
):
    """
        given : access 외 type JWT
        when : verification request
        then : invalid request error
    """
    user_id = create_user.id
    token = make_custom_jwt(obj=user_id, token_type="wrong")
    dto = GetVerificationDto(token=token, uuid=uuid)

    result = VerificationJWTUseCase().execute(dto=dto)
    assert result.message == FailureType.INVALID_REQUEST_ERROR


def test_verification_token_when_detected_blacklist_then_response_401(
    session, create_user
):
    """
        given : invalid access_token, blacklist in DB
        when : verification requset
        then : unauthorized_error
    """
    user_id = create_user.id

    token = create_invalid_access_token(user_id=user_id)

    verification_dto = GetVerificationDto(token=token, uuid=uuid)
    blacklist_dto = GetBlacklistDto(user_id=user_id, access_token=token.decode("UTF-8"))

    AuthenticationRepository().create_blacklist(dto=blacklist_dto)

    result = VerificationJWTUseCase().execute(dto=verification_dto)

    assert result.message == FailureType.UNAUTHORIZED_ERROR


# def test_verification_when_get_expired_access_token_then_success(
#     session, create_user_dto
# ):
#     """
#         given : expired access_token, valid refresh_token in DB
#         when : verification request
#         then : success
#     """
#
#     CreateUserUseCase().execute(dto=create_user_dto)
#     user: UserEntity | None = session.query(UserModel).filter_by(id=1).first()
#
#     expired_token = create_invalid_access_token(user_id=user.id)
#     valid_refresh_token = create_refresh_token(identity=user.id)
#
#     jwt_model = JwtModel(
#         user_id=user.id, access_token=expired_token, refresh_token=valid_refresh_token,
#     )
#     session.add(jwt_model)
#     session.commit()
#
#     verification_dto = GetVerificationDto(token=expired_token, uuid=uuid)
#
#     result = VerificationJWTUseCase().execute(dto=verification_dto)
#
#     assert result.type == "success"
#     assert isinstance(result, UseCaseSuccessOutput)
#     assert b"access_token" in result.value.data
#
#
# def test_verification_when_get_expired_access_token_with_expired_refresh_token_then_401(
#     session, create_user_dto
# ):
#     """
#         given : expired access_token, user_id, expired refresh_token(in DB)
#         when : verification request
#         then : response 401
#     """
#     CreateUserUseCase().execute(dto=create_user_dto)
#     user: UserEntity | None = UserRepository().get_user_by_id(id=1)
#
#     expired_token = create_invalid_access_token(user_id=user.id)
#
#     verification_dto = GetVerificationDto(token=expired_token, uuid=uuid)
#
#     with patch(
#         "core.domains.authentication.use_case.v1.auth_use_case.VerificationJWTUseCase._is_valid_refresh_token"
#     ) as mock_is_valid_refresh_token:
#         mock_is_valid_refresh_token.return_value = False
#         result = VerificationJWTUseCase().execute(dto=verification_dto)
#
#     assert result.message == FailureType.UNAUTHORIZED_ERROR
#
#
# def test_verification_when_get_out_user_then_401(session, create_user_dto):
#     """
#         given : expired access_token, user.is_out=True, valid refresh_token(in DB)
#         when : verification request
#         then : response 401
#     """
#     CreateUserUseCase().execute(dto=create_user_dto)
#     user: UserEntity | None = UserRepository().get_user_by_id(id=1)
#
#     UserRepository().update_user_is_out(user_id=user.id, status=True)
#
#     expired_token = create_invalid_access_token(user_id=user.id)
#     verification_dto = GetVerificationDto(token=expired_token, uuid=uuid)
#
#     result = VerificationJWTUseCase().execute(dto=verification_dto)
#
#     assert result.message == FailureType.UNAUTHORIZED_ERROR
#
#
# def test_verification_when_get_no_user_then_404(session, create_user_dto):
#     """
#         given : expired access_token, valid refresh_token(in DB), but None user
#         when : verification request
#         then : response 404
#     """
#     CreateUserUseCase().execute(dto=create_user_dto)
#     user: UserEntity | None = UserRepository().get_user_by_id(id=1)
#
#     expired_token = create_invalid_access_token(user_id=user.id)
#     verification_dto = GetVerificationDto(token=expired_token, uuid=uuid)
#
#     with patch(
#         "core.domains.user.repository.user_repository.UserRepository.get_user_by_id"
#     ) as mock_get_user_by_id:
#         mock_get_user_by_id.return_value = None
#         result = VerificationJWTUseCase().execute(dto=verification_dto)
#
#     assert result.message == FailureType.NOT_FOUND_ERROR
