import datetime

import inject
from flask_jwt_extended import create_access_token

from app.extensions.utils.enum.jwt_enum import JWTEnum
from core.domains.authentication.repository.auth_repository import (
    AuthenticationRepository,
)
from core.domains.oauth.dto.oauth_dto import GetOAuthLoginDto, GetOAuthAdminLoginDto
from core.domains.oauth.entity.oauth_entity import OAuthLoginEntity
from core.domains.user.entity.user_entity import UserEntity
from core.domains.user.enum.user_enum import UserGroupEnum
from core.domains.user.repository.user_repository import UserRepository
from core.use_case_output import UseCaseSuccessOutput, UseCaseFailureOutput, FailureType


class CreateGuestJWTUseCase:
    @inject.autoparams()
    def __init__(
        self, user_repo: UserRepository, auth_repo: AuthenticationRepository,
    ):
        self._user_repo = user_repo
        self._auth_repo = auth_repo

    def execute(
        self, dto: GetOAuthLoginDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        """
        DB Create -> X
        JWT identify -> guest
        기존 유저 여부 로직 추가 -> 기존 유저인 경우 Guest JWT가 아닌 해당 유저 JWT 발급
        로그아웃 후 재로그인 유저 -> is_out 처리
        """

        # 기존 유저인 경우
        found_user_id: int | None = self._user_repo.find_user_id_by_provider_id(
            provider_id=dto.provider_id, provider=dto.provider
        )

        if found_user_id:
            user: UserEntity = self._user_repo.get_user_by_id(found_user_id)
            # if user.is_out and user.is_available:
            #     self._user_repo.update_user_is_out(user_id=user.id, status=False)

            if not user.is_available:
                return UseCaseFailureOutput(
                    type="Invalid user: user is not available",
                    message=FailureType.UNAUTHORIZED_ERROR,
                )

            self._auth_repo.update_jwt(user.id)
            token_info = self._auth_repo.get_jwt(user.id)

            # login_uuid update
            self._user_repo.update_user_uuid(user_id=user.id, login_uuid=dto.uuid)
            self._user_repo.update_current_connection_time(user_id=user.id)

            result = OAuthLoginEntity(
                access_token=token_info.access_token, provider_id=None,
            )
        else:
            # 신규 유저인 경우 guest token 생성
            provider_id: str = self._user_repo.get_crypt_provider_id(
                provider_id=dto.provider_id
            )

            result = OAuthLoginEntity(
                access_token=create_access_token(JWTEnum.GUEST_IDENTIFY.value),
                provider_id=provider_id,
            )

        return UseCaseSuccessOutput(value=result.dict())


class CreateAdminJWTUseCase:
    @inject.autoparams()
    def __init__(
        self, user_repo: UserRepository, auth_repo: AuthenticationRepository,
    ):
        self._user_repo = user_repo
        self._auth_repo = auth_repo

    def execute(
        self, dto: GetOAuthAdminLoginDto
    ) -> UseCaseSuccessOutput | UseCaseFailureOutput:
        # 기존 유저인 경우
        found_user_id: int | None = self._user_repo.find_user_id_by_provider_id(
            provider_id=dto.provider_id, provider=dto.provider
        )

        result = None
        if found_user_id:
            user: UserEntity = self._user_repo.get_user_by_id(found_user_id)
            if user.group != UserGroupEnum.ADMIN.value:
                return UseCaseFailureOutput(
                    type="not an administrator", message=FailureType.UNAUTHORIZED_ERROR,
                )

            access_token = create_access_token(
                identity=user.id, expires_delta=datetime.timedelta(minutes=30)
            )
            self._user_repo.update_current_connection_time(user_id=user.id)

            result = OAuthLoginEntity(access_token=access_token, provider_id=None,)

        return UseCaseSuccessOutput(value=result.dict())
