# Path: pynubank/auth_mode.py
# class AuthMode(Enum):
#     UNAUTHENTICATED = 0
#     WEB = 1
#     APP = 2
# 
# def requires_auth_mode(*required_auth_mode: AuthMode):
#     def decorator(function):
#         @wraps(function)
#         def wrapper(*args, **kwargs):
#             instance = args[0]
#             if instance._auth_mode not in required_auth_mode:
#                 raise NuInvalidAuthenticationMethod(
#                     'The authentication method used doest not allow access to this resource'
#                 )
# 
#             return function(*args, **kwargs)
# 
#         return wrapper
# 
#     return decorator
# 
# Path: pynubank/exception.py
# class NuMissingCreditCard(NuException):
#     def __init__(self):
#         super().__init__(f'Couldn\'t fetch bills due to missing credit card.')
# 
# Path: pynubank/utils/discovery.py
# class Discovery:
#     def __init__(self, client: HttpClient):
#         self.client = client
#         self.proxy_list_url = {}
#         self.proxy_list_app_url = {}
# 
#         self._update_proxy_urls()
# 
#     def get_url(self, name: str) -> str:
#         return self._get_url(name, self.proxy_list_url)
# 
#     def get_app_url(self, name: str) -> str:
#         return self._get_url(name, self.proxy_list_app_url)
# 
#     def _update_proxy_urls(self):
#         self.proxy_list_url = self.client.get(DISCOVERY_URL)
#         self.proxy_list_app_url = self.client.get(DISCOVERY_APP_URL)
# 
#     def _get_url(self, name: str, target: dict) -> str:
#         url = target.get(name)
#         if not url:
#             raise NuException(f'There is no URL discovered for {name}')
# 
#         return url
# 
# Path: pynubank/utils/graphql.py
# def prepare_request_body(graphql_object, variables=None):
#     if variables is None:
#         variables = {}
# 
#     return OrderedDict({
#         'variables': variables,
#         'query': _get_query(graphql_object)
#     })
# 
# Path: pynubank/utils/http.py
# class HttpClient:
# 
#     def __init__(self):
#         self._cert = None
#         self._headers = {
#             'Content-Type': 'application/json',
#             'X-Correlation-Id': 'WEB-APP.pewW9',
#             'User-Agent': 'pynubank Client - https://github.com/andreroggeri/pynubank',
#         }
# 
#     def set_cert(self, cert_path: str):
#         self._cert = cert_path
# 
#     def set_header(self, name: str, value: str):
#         self._headers[name] = value
# 
#     def remove_header(self, name: str):
#         self._headers.pop(name)
# 
#     def get_header(self, name: str):
#         return self._headers.get(name)
# 
#     @property
#     def _cert_args(self):
#         return {'pkcs12_filename': self._cert, 'pkcs12_password': ''} if self._cert else {}
# 
#     def _handle_response(self, response: Response) -> dict:
#         if response.status_code != 200:
#             raise NuRequestException(response)
# 
#         return response.json()
# 
#     def raw_get(self, url: str) -> Response:
#         return get(url, headers=self._headers, **self._cert_args)
# 
#     def get(self, url: str) -> dict:
#         return self._handle_response(self.raw_get(url))
# 
#     def post(self, url: str, json: dict) -> dict:
#         return self._handle_response(post(url, json=json, headers=self._headers, **self._cert_args))
# 
# Path: pynubank/utils/parsing.py
# def parse_float(value: str):
#     return float(re.search(r'(?:\d*\.)*\d+,\d{1,2}', value).group().replace('.', '').replace(',', '.'))
# 
# def parse_pix_transaction(transaction: dict) -> dict:
#     if transaction['__typename'] != 'GenericFeedEvent':
#         return transaction
# 
#     if transaction['title'] in PIX_TRANSACTION_MAP.keys():
#         transaction['__typename'] = PIX_TRANSACTION_MAP[transaction['title']]
#         transaction['amount'] = parse_float(transaction['detail'])
# 
#     return transaction


import calendar
import datetime
import itertools
import uuid
from typing import Tuple
from qrcode import QRCode
from pynubank.auth_mode import AuthMode, requires_auth_mode
from pynubank.exception import NuMissingCreditCard
from pynubank.utils.discovery import Discovery
from pynubank.utils.graphql import prepare_request_body
from pynubank.utils.http import HttpClient
from pynubank.utils.parsing import parse_float, parse_pix_transaction
        self._save_auth_data(response)
        self._auth_mode = AuthMode.APP

        return response.get('refresh_token')

    def revoke_token(self):
        self._client.post(self._revoke_token_url, {})

        self._client.remove_header('Authorization')

    @requires_auth_mode(AuthMode.APP, AuthMode.WEB)
    def get_card_feed(self):
        return self._client.get(self._feed_url)

    @requires_auth_mode(AuthMode.APP, AuthMode.WEB)
    def get_card_statements(self):
        feed = self.get_card_feed()
        return list(filter(lambda x: x['category'] == 'transaction', feed['events']))

    @requires_auth_mode(AuthMode.APP, AuthMode.WEB)
    def get_card_payments(self):
        feed = self.get_card_feed()
        return list(filter(lambda x: x['category'] == 'payment', feed['events']))

    @requires_auth_mode(AuthMode.APP, AuthMode.WEB)
    def get_bills(self):
        if self._bills_url is not None:
            request = self._client.get(self._bills_url)
            return request['bills']
        else:

# Path: pynubank/auth_mode.py
# class AuthMode(Enum):
#     UNAUTHENTICATED = 0
#     WEB = 1
#     APP = 2
# 
# def requires_auth_mode(*required_auth_mode: AuthMode):
#     def decorator(function):
#         @wraps(function)
#         def wrapper(*args, **kwargs):
#             instance = args[0]
#             if instance._auth_mode not in required_auth_mode:
#                 raise NuInvalidAuthenticationMethod(
#                     'The authentication method used doest not allow access to this resource'
#                 )
# 
#             return function(*args, **kwargs)
# 
#         return wrapper
# 
#     return decorator
# 
# Path: pynubank/exception.py
# class NuMissingCreditCard(NuException):
#     def __init__(self):
#         super().__init__(f'Couldn\'t fetch bills due to missing credit card.')
# 
# Path: pynubank/utils/discovery.py
# class Discovery:
#     def __init__(self, client: HttpClient):
#         self.client = client
#         self.proxy_list_url = {}
#         self.proxy_list_app_url = {}
# 
#         self._update_proxy_urls()
# 
#     def get_url(self, name: str) -> str:
#         return self._get_url(name, self.proxy_list_url)
# 
#     def get_app_url(self, name: str) -> str:
#         return self._get_url(name, self.proxy_list_app_url)
# 
#     def _update_proxy_urls(self):
#         self.proxy_list_url = self.client.get(DISCOVERY_URL)
#         self.proxy_list_app_url = self.client.get(DISCOVERY_APP_URL)
# 
#     def _get_url(self, name: str, target: dict) -> str:
#         url = target.get(name)
#         if not url:
#             raise NuException(f'There is no URL discovered for {name}')
# 
#         return url
# 
# Path: pynubank/utils/graphql.py
# def prepare_request_body(graphql_object, variables=None):
#     if variables is None:
#         variables = {}
# 
#     return OrderedDict({
#         'variables': variables,
#         'query': _get_query(graphql_object)
#     })
# 
# Path: pynubank/utils/http.py
# class HttpClient:
# 
#     def __init__(self):
#         self._cert = None
#         self._headers = {
#             'Content-Type': 'application/json',
#             'X-Correlation-Id': 'WEB-APP.pewW9',
#             'User-Agent': 'pynubank Client - https://github.com/andreroggeri/pynubank',
#         }
# 
#     def set_cert(self, cert_path: str):
#         self._cert = cert_path
# 
#     def set_header(self, name: str, value: str):
#         self._headers[name] = value
# 
#     def remove_header(self, name: str):
#         self._headers.pop(name)
# 
#     def get_header(self, name: str):
#         return self._headers.get(name)
# 
#     @property
#     def _cert_args(self):
#         return {'pkcs12_filename': self._cert, 'pkcs12_password': ''} if self._cert else {}
# 
#     def _handle_response(self, response: Response) -> dict:
#         if response.status_code != 200:
#             raise NuRequestException(response)
# 
#         return response.json()
# 
#     def raw_get(self, url: str) -> Response:
#         return get(url, headers=self._headers, **self._cert_args)
# 
#     def get(self, url: str) -> dict:
#         return self._handle_response(self.raw_get(url))
# 
#     def post(self, url: str, json: dict) -> dict:
#         return self._handle_response(post(url, json=json, headers=self._headers, **self._cert_args))
# 
# Path: pynubank/utils/parsing.py
# def parse_float(value: str):
#     return float(re.search(r'(?:\d*\.)*\d+,\d{1,2}', value).group().replace('.', '').replace(',', '.'))
# 
# def parse_pix_transaction(transaction: dict) -> dict:
#     if transaction['__typename'] != 'GenericFeedEvent':
#         return transaction
# 
#     if transaction['title'] in PIX_TRANSACTION_MAP.keys():
#         transaction['__typename'] = PIX_TRANSACTION_MAP[transaction['title']]
#         transaction['amount'] = parse_float(transaction['detail'])
# 
#     return transaction


# Path: pynubank/nubank.py
import calendar
import datetime
import itertools
import uuid
from typing import Tuple
from qrcode import QRCode
from pynubank.auth_mode import AuthMode, requires_auth_mode
from pynubank.exception import NuMissingCreditCard
from pynubank.utils.discovery import Discovery
from pynubank.utils.graphql import prepare_request_body
from pynubank.utils.http import HttpClient
from pynubank.utils.parsing import parse_float, parse_pix_transaction

        self._save_auth_data(response)
        self._auth_mode = AuthMode.APP

        return response.get('refresh_token')

    def revoke_token(self):
        self._client.post(self._revoke_token_url, {})

        self._client.remove_header('Authorization')

    @requires_auth_mode(AuthMode.APP, AuthMode.WEB)
    def get_card_feed(self):
        return self._client.get(self._feed_url)

    @requires_auth_mode(AuthMode.APP, AuthMode.WEB)
    def get_card_statements(self):
        feed = self.get_card_feed()
        return list(filter(lambda x: x['category'] == 'transaction', feed['events']))

    @requires_auth_mode(AuthMode.APP, AuthMode.WEB)
    def get_card_payments(self):
        feed = self.get_card_feed()
        return list(filter(lambda x: x['category'] == 'payment', feed['events']))

    @requires_auth_mode(AuthMode.APP, AuthMode.WEB)
    def get_bills(self):
        if self._bills_url is not None:
            request = self._client.get(self._bills_url)
            return request['bills']
        else:

            raise NuMissingCreditCard