from flask import Blueprint, render_template, request, redirect, url_for, flash, make_response, jsonify, abort, after_this_request
from config import Config
from app.models.user import User
from app.models.gameservers import GameServer
from app.models.place import Place
from app.models.universe import Universe
from app.models.legacy_data_persistence import LegacyDataPersistence
from app.extensions import redis_controller, get_remote_address, csrf, limiter, db
from datetime import datetime
import logging
import gzip

LegacyDataPersistenceRoute = Blueprint('legacyDataPersistence', __name__, url_prefix='/persistence/legacy')

@LegacyDataPersistenceRoute.before_request
def before_request():
    if "Roblox/" not in request.user_agent.string:
        logging.info(f"LegacyDataPersistence - UserAgent {request.user_agent} - Not allowed")
        abort(404)
    RemoteAddress = get_remote_address()
    GameServerObj : GameServer = GameServer.query.filter_by( serverIP = RemoteAddress ).first()
    if GameServerObj is None:
        logging.info(f"LegacyDataPersistence - {RemoteAddress} - Not found")
        abort(404)
    
    if "Roblox-Place-Id" not in request.headers and "placeId" not in request.args:
        logging.info(f"LegacyDataPersistence - GameServer {RemoteAddress} - Roblox-Place-Id header and cookie not found")
        abort(404)
    
    PlaceId = request.headers.get( key = "Roblox-Place-Id", default = None, type = int ) or request.args.get( key = "placeId", default = None, type = int )
    if PlaceId is None:
        logging.info(f"LegacyDataPersistence - GameServer {RemoteAddress} - Roblox-Place-Id header or arg not expected type")
        abort(404)
    
    PlaceObj : Place = Place.query.filter_by( placeid = PlaceId ).first()
    if PlaceObj is None:
        logging.info(f"LegacyDataPersistence - Place {PlaceId} - Place not found")
        abort(404)

@LegacyDataPersistenceRoute.route('/load', methods=['POST', 'GET'])
@csrf.exempt
def LoadData():
    PlaceId = request.headers.get( key = "Roblox-Place-Id", default = None, type = int ) or request.args.get( key = "placeId", default = None, type = int )

    RequestedUserId = request.args.get(
        key = "userId",
        default = None,
        type = int
    )
    if RequestedUserId is None:
        return "Invalid request", 400
    
    UserObj : User = User.query.filter_by( id = RequestedUserId ).first()
    if UserObj is None:
        return "Invalid request", 400
    
    PlaceObj : Place = Place.query.filter_by( placeid = PlaceId ).first()
    if PlaceObj is None:
        return "Invalid request", 400
    UniverseObj : Universe = Universe.query.filter_by( id = PlaceObj.parent_universe_id ).first()
    if UniverseObj is None:
        return "Invalid request", 400
    
    LegacyDataPersistenceObj : LegacyDataPersistence = LegacyDataPersistence.query.filter_by(
        userid = RequestedUserId,
        universe_id = UniverseObj.id
    ).first()
    logging.info(f"LegacyDataPersistence - User {UserObj.id} - Place {PlaceId} - Universe {UniverseObj.id} - Data requested")
    if LegacyDataPersistenceObj is None:
        return "", 200
    
    return gzip.decompress(LegacyDataPersistenceObj.data), 200

@LegacyDataPersistenceRoute.route('/save', methods=['POST'])
@csrf.exempt
def SaveData():
    PlaceId = request.headers.get( key = "Roblox-Place-Id", default = None, type = int ) or request.args.get( key = "placeId", default = None, type = int )

    PayloadData = request.data
    if request.content_encoding != "gzip":
        PayloadData = gzip.compress( PayloadData )

    RequestedUserId = request.args.get(
        key = "userId",
        default = None,
        type = int
    )
    if RequestedUserId is None:
        return "Invalid request", 400
    
    UserObj : User = User.query.filter_by( id = RequestedUserId ).first()
    if UserObj is None:
        return "Invalid request", 400
    
    if len(PayloadData) > 1024 * 1024 * 2:
        logging.info(f"LegacyDataPersistence - User {UserObj.id} - Place {PlaceId} - Universe {UniverseObj.id} - Payload too large, {len(PayloadData)} bytes")
        return "Payload too large", 400
    
    PlaceObj : Place = Place.query.filter_by( placeid = PlaceId ).first()
    if PlaceObj is None:
        return "Invalid request", 400
    UniverseObj : Universe = Universe.query.filter_by( id = PlaceObj.parent_universe_id ).first()
    if UniverseObj is None:
        return "Invalid request", 400

    LegacyDataPersistenceObj : LegacyDataPersistence = LegacyDataPersistence.query.filter_by(
        userid = RequestedUserId,
        universe_id = UniverseObj.id
    ).first()

    if LegacyDataPersistenceObj is None:
        LegacyDataPersistenceObj = LegacyDataPersistence(
            placeid = PlaceId,
            userid = RequestedUserId,
            universe_id = UniverseObj.id
        )
        db.session.add( LegacyDataPersistenceObj )
    
    LegacyDataPersistenceObj.data = PayloadData
    LegacyDataPersistenceObj.last_updated = datetime.utcnow()
    db.session.commit()
    logging.info(f"LegacyDataPersistence - User {UserObj.id} - Place {PlaceId} - Universe {UniverseObj.id} - Saved {len(LegacyDataPersistenceObj.data)} bytes")
    return "OK", 200
    
    