import os
import io
import time
import uuid
import logging
import threading
from functools import lru_cache

from flask import Flask, request, send_file, jsonify, after_this_request
from PIL import Image
import UnityPy

# ----------------------------------------------------------------------------
# App setup
# ----------------------------------------------------------------------------
app = Flask(__name__)
application = app

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
)
log = logging.getLogger("gloowall")

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
TMP_DIR = os.path.join(BASE_DIR, "tmp")
os.makedirs(TMP_DIR, exist_ok=True)

FILE_FF = os.path.join(BASE_DIR, "ff", "base.unity3d")
FILE_MAX = os.path.join(BASE_DIR, "max", "base.unity3d")

PATH_IDS = [-1430620519988073320, 8636872379075887098]

GAME_CONFIG = {
    "FF": {"path": FILE_FF, "target_size": 2730799},
    "MAX": {"path": FILE_MAX, "target_size": 2855141},
}

MAX_UPLOAD_BYTES = 15 * 1024 * 1024  
app.config["MAX_CONTENT_LENGTH"] = MAX_UPLOAD_BYTES

_base_bytes_cache = {}
_base_bytes_lock = threading.Lock()

def get_base_bytes(game_type: str) -> bytes:
    if game_type not in _base_bytes_cache:
        with _base_bytes_lock:
            if game_type not in _base_bytes_cache:
                path = GAME_CONFIG[game_type]["path"]
                if not os.path.exists(path):
                    raise FileNotFoundError(f"Base unity file missing: {path}")
                with open(path, "rb") as f:
                    _base_bytes_cache[game_type] = f.read()
                log.info("Cached base file for %s", game_type)
    return _base_bytes_cache[game_type]

def pad_file(data_bytes: bytes, target_size: int) -> bytes:
    current_size = len(data_bytes)
    if current_size < target_size:
        return data_bytes + b"\x00" * (target_size - current_size)
    elif current_size > target_size:
        return data_bytes[:target_size]
    return data_bytes

@app.route("/", methods=["GET"])
def home():
    return "AG Gloowall API Server is Active & Running! ЁЯЪА"

@app.route("/create_gloowall", methods=["POST"])
def create_gloowall():
    start_time = time.time()
    uid = uuid.uuid4().hex
    output_unity_path = os.path.join(TMP_DIR, f"output_{uid}.unity3d")

    @after_this_request
    def cleanup(response):
        if os.path.exists(output_unity_path):
            try:
                os.remove(output_unity_path)
            except Exception:
                pass
        return response

    game_type = request.form.get("game", "FF").upper()
    if game_type not in GAME_CONFIG:
        return jsonify({"error": "Unknown game type."}), 400

    image_file = request.files.get("texture")
    if not image_file or image_file.filename == "":
        return jsonify({"error": "No image uploaded"}), 400

    try:
        img_bytes = image_file.read()
        try:
            img = Image.open(io.BytesIO(img_bytes)).convert("RGBA")
            # ЁЯФе OPTIMIZATION: ржЗржорзЗржЬ рж╕рж╛ржЗржЬ 512x512 ржХрж░рж╛ рж╣рж▓рзЛ (ржкрзНрж░рж╕рзЗрж╕рж┐ржВ рж╕рзНржкрж┐ржб ржЕржирзЗржХ ржжрзНрж░рзБржд рж╣ржмрзЗ)
            img.thumbnail((512, 512), Image.Resampling.LANCZOS)
        except Exception:
            return jsonify({"error": "Invalid image"}), 400

        cfg = GAME_CONFIG[game_type]
        target_size = cfg["target_size"]
        
        try:
            base_bytes = get_base_bytes(game_type)
        except FileNotFoundError as e:
            return jsonify({"error": str(e)}), 500

        env = UnityPy.load(io.BytesIO(base_bytes))
        modified = False
        for obj in env.objects:
            if obj.type.name == "Texture2D" and obj.path_id in PATH_IDS:
                data = obj.read()
                data.image = img
                data.save()
                modified = True

        if not modified:
            return jsonify({"error": "Texture Path ID not found"}), 500

        out_bytes = env.file.save(packer="lzma")
        final_data = pad_file(out_bytes, target_size)

        with open(output_unity_path, "wb") as f:
            f.write(final_data)

        log.info("Finished in %.2fs", time.time() - start_time)

        return send_file(
            output_unity_path,
            mimetype="application/octet-stream",
            as_attachment=True,
            download_name="modified_gloowall.unity3d",
        )

    except Exception as e:
        return jsonify({"error": str(e)}), 500

if __name__ == "__main__":
    for gt in GAME_CONFIG:
        try:
            get_base_bytes(gt)
        except FileNotFoundError:
            pass
    app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)), threaded=True)
