from flask import Flask
from flask_restx import Api 
from flask_cors import CORS
from flask_mail import Mail
from flask_mongoengine import MongoEngine
from flask_jwt_extended import JWTManager

from app.config.settings import Config
from app.resources.v1.auth import auth_namespace

from app.services.token import TokenService
from app.services.auth import AuthService

# Initialize Flask 
app = Flask(__name__)

app.config['TEMPLATES_AUTO_RELOAD'] = True
app.config['TEMPLATES_FOLDER'] = 'templates'

# Configure app using your Config class
app.config.from_object(Config())

# Add the token to the Swagger documentation
authorizations = {
    'Bearer Token': {
        'type': 'apiKey',
        'in': 'header',
        'name': 'Authorization',
        'description': "Type in the *'Value'* input box below: **'Bearer &lt;JWT&gt;'**, where JWT is the token"
    }
}

# Initialize Flask API
api = Api(
    app,
    title='Authentication Service API',
    version='1.0',
    description='<p>The Authentication Service API is dedicated to user authentication and access control.</p>'
                '<p>It provides secure and robust authentication mechanisms for user login, registration, and management.</p>'
                '<p>This service ensures the protection of user data and identity, making it an ideal solution for building a secure user authentication system for your applications.</p>',
    authorizations=authorizations,
    doc='/swagger',
    prefix='/api'
)

# Initialize Flask-CORS
cors = CORS(app)

# Initialize the MongoEngine
db = MongoEngine(app) 

# Initialize the JWTManager
jwt = JWTManager(app)

# Initialize the mailer
mail = Mail(app)

# Add namespaces
api.add_namespace(auth_namespace)


# Callback function to check if a JWT exists in the database blocklist
@jwt.token_in_blocklist_loader
def check_if_token_revoked(jwt_header, jwt_payload: dict) -> bool:
    # Get the JWT ID (jti) from the JWT payload
    jti = jwt_payload["jti"]
    
    # Get the user ID (sub) from the JWT payload
    current_user_id = jwt_payload.get("sub") 

    # Check if the token is blacklisted using the app's blacklist_model
    return TokenService.is_blacklisted(AuthService.get_user_by_email(current_user_id), jti)

# Callback function for revoked tokens
@jwt.revoked_token_loader
def revoked_token_callback(jwt_header, jwt_payload):
    # Return a response indicating that the token is blacklisted and unauthorized
    return {
        "msg": "Token blacklisted. Please log in again..", 
    }, 401 # Unauthorized

@app.route('/')
def home():
    return "<h1>Welcome to the Authentication Service API</h1><p>Go to <a href='/swagger'>Swagger UI</a></p>"

# Define a custom error handler for the 404 Not Found error using the @app.errorhandler decorator.
# Define a custom error handler.
@app.errorhandler(500)
def internal_server_error(e):
    return {
        "error": "Internal Server Error",
        "msg": "An internal server error occurred while processing your request."
    }, 500  # HTTP status code 500 (Internal Server Error)

@app.errorhandler(400)
def bad_request_error(e):
    return {
        "error": "Bad Request",
        "msg": "The request you made was invalid. Please check your input data and try again."
    }, 400  # HTTP status code 400 (Bad Request)

@app.errorhandler(401)
def unauthorized_error(e):
    return {
        "error": "Unauthorized",
        "msg": "You are not authorized to access this resource. Please log in and provide valid credentials."
    }, 401  # HTTP status code 401 (Unauthorized)

@app.errorhandler(403)
def forbidden_error(e):
    return {
        "error": "Forbidden",
        "msg": "You do not have permission to access this resource."
    }, 403  # HTTP status code 403 (Forbidden)

@app.errorhandler(404)
def page_not_found(e):
    # Create a JSON response with an error message and a 404 status code.
    return {
        "error": "Not Found",  # Error type: Not Found
        "msg": "The requested URL was not found on the server."  # Error message
    }, 404  # HTTP status code 404 (Not Found)




