from flask import Blueprint, render_template, request, redirect, url_for, flash, session, abort, jsonify, make_response
from app.util import auth
from app.extensions import db, csrf, limiter
from flask_wtf.csrf import CSRFError, generate_csrf
from datetime import datetime, timedelta

from app.models.user_email import UserEmail
from app.models.user import User
from app.models.placeserver_players import PlaceServerPlayer
from app.models.placeservers import PlaceServer
from app.models.place import Place
from app.models.asset import Asset

PresenceAPIRoute = Blueprint('presenceapiroute', __name__, url_prefix='/')

csrf.exempt(PresenceAPIRoute)
@PresenceAPIRoute.errorhandler(CSRFError)
def handle_csrf_error(e):
    ErrorResponse = make_response(jsonify({
        "errors": [
            {
                "code": 0,
                "message": "Token Validation Failed"
            }
        ]
    }))

    ErrorResponse.status_code = 403
    ErrorResponse.headers["x-csrf-token"] = generate_csrf()
    return ErrorResponse

@PresenceAPIRoute.errorhandler(429)
def handle_ratelimit_reached(e):
    return jsonify({
        "errors": [
            {
                "code": 9,
                "message": "The flood limit has been exceeded."
            }
        ]
    }), 429

@PresenceAPIRoute.before_request
def before_request():
    if "Roblox/" not in request.user_agent.string:
        csrf.protect()

@PresenceAPIRoute.route("/v1/presence/users", methods=["POST"])
@auth.authenticated_required_api
@limiter.limit("30/minute")
def multi_get_users_presence():
    if not request.is_json:
        return jsonify({"errors": [{"code": 0,"message": "Invalid Request"}]}), 400
    
    if "userIds" not in request.json:
        return jsonify({"errors": [{"code": 0,"message": "Invalid Request"}]}), 400
    
    userIds = request.json["userIds"]

    if type(userIds) is not list:
        return jsonify({"errors": [{"code": 0,"message": "Invalid Request"}]}), 400

    if len(userIds) > 100:
        return jsonify({"errors": [{"code": 0,"message": "Invalid Request"}]}), 400
    
    requestedData = []
    for userId in userIds:
        try:
            userId = int(userId)
        except:
            return jsonify({"errors": [{"code": 1,"message": "Invalid UserId"}]}), 400
        userObject : User = User.query.filter_by(id=userId).first()
        if userObject is None:
            return jsonify({"errors": [{"code": 1,"message": "Invalid UserId"}]}), 400
        else:
            isUserOnline = userObject.lastonline > datetime.utcnow() - timedelta(minutes=1)
            UserPlaceServerPlayerObj : PlaceServerPlayer | None = PlaceServerPlayer.query.filter_by( userid = userId ).first()
            isUserInGame = UserPlaceServerPlayerObj is not None
            userPresenceType = 2 if isUserInGame else 1 if isUserOnline else 0

            PlaceServerHost : PlaceServer | None = None
            PlaceObject : Place | None = None

            if isUserInGame:
                PlaceServerHost : PlaceServer = PlaceServer.query.filter_by( serveruuid = UserPlaceServerPlayerObj.serveruuid ).first()
                if PlaceServerHost is not None:
                    PlaceObject : Place = Place.query.filter_by( placeid = PlaceServerHost.serverPlaceId ).first()
                    PlaceAssetObj : Asset = PlaceObject.assetObj
                else:
                    PlaceAssetObj = None
                    UserPlaceServerPlayerObj = None

            requestedData.append({
                "userPresenceType": userPresenceType,
                "lastLocation": "Website" if not isUserInGame else PlaceAssetObj.name,
                "placeId": PlaceAssetObj.id if isUserInGame else None,
                "rootPlaceId": PlaceAssetObj.id if isUserInGame else None,
                "gameId": PlaceServerHost.serveruuid if isUserInGame else None,
                "userId": userId,
                "lastOnline": userObject.lastonline.strftime("%Y-%m-%dT%H:%M:%S.000Z"),
            })
    
    return jsonify({
        "userPresences": requestedData
    }), 200