"""
Scribus Bridge Server — HTTP API for controlling Scribus from rSpace.

Architecture:
  rspace container → HTTP → this Flask server (port 8765)
                              │ Unix socket
                    scribus --python-script scribus_runner.py

The runner script executes inside the Scribus process (required by Scribus
Python API). It listens on a Unix socket for JSON commands. This Flask
server translates HTTP requests into socket commands.
"""

import json
import os
import socket
import time
from pathlib import Path
from flask import Flask, request, jsonify

app = Flask(__name__)

BRIDGE_SECRET = os.environ.get("BRIDGE_SECRET", "")
SOCKET_PATH = "/tmp/scribus_bridge.sock"
DESIGNS_DIR = Path("/data/designs")


def _check_auth():
    """Verify X-Bridge-Secret header."""
    if not BRIDGE_SECRET:
        return None  # No secret configured, allow all
    token = request.headers.get("X-Bridge-Secret", "")
    if token != BRIDGE_SECRET:
        return jsonify({"error": "Unauthorized"}), 401
    return None


def _send_command(cmd: dict, timeout: float = 30.0) -> dict:
    """Send a JSON command to the Scribus runner via Unix socket."""
    if not os.path.exists(SOCKET_PATH):
        return {"error": "Scribus runner not connected. Call /api/scribus/start first."}

    try:
        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        sock.settimeout(timeout)
        sock.connect(SOCKET_PATH)
        payload = json.dumps(cmd) + "\n"
        sock.sendall(payload.encode("utf-8"))

        # Read response (newline-delimited JSON)
        buf = b""
        while True:
            chunk = sock.recv(4096)
            if not chunk:
                break
            buf += chunk
            if b"\n" in buf:
                break
        sock.close()
        return json.loads(buf.decode("utf-8").strip())
    except socket.timeout:
        return {"error": "Command timed out"}
    except ConnectionRefusedError:
        return {"error": "Scribus runner not responding"}
    except Exception as e:
        return {"error": f"Bridge error: {str(e)}"}


@app.before_request
def before_request():
    auth = _check_auth()
    if auth:
        return auth


@app.route("/health", methods=["GET"])
def health():
    runner_alive = os.path.exists(SOCKET_PATH)
    return jsonify({
        "ok": True,
        "service": "scribus-bridge",
        "runner_connected": runner_alive,
    })


@app.route("/api/scribus/start", methods=["POST"])
def start_scribus():
    """Verify runner socket is available. Optionally launch Scribus GUI for real rendering."""
    # The runner process is managed by supervisor and should already be listening.
    # Wait briefly for socket if it's still starting up.
    for _ in range(10):
        if os.path.exists(SOCKET_PATH):
            return jsonify({"ok": True, "message": "Runner connected", "runner_connected": True})
        time.sleep(0.5)

    return jsonify({"ok": False, "error": "Runner socket not available. Check supervisor logs."}), 500


@app.route("/api/scribus/command", methods=["POST"])
def scribus_command():
    """Execute a Scribus command via the runner."""
    body = request.get_json(silent=True)
    if not body or "action" not in body:
        return jsonify({"error": "Missing 'action' in request body"}), 400

    result = _send_command(body)
    status = 200 if "error" not in result else 500
    return jsonify(result), status


@app.route("/api/scribus/state", methods=["GET"])
def scribus_state():
    """Return the full document state as JSON."""
    result = _send_command({"action": "get_doc_state"})
    status = 200 if "error" not in result else 500
    return jsonify(result), status


@app.route("/api/scribus/screenshot", methods=["GET"])
def scribus_screenshot():
    """Export the current page as PNG."""
    dpi = request.args.get("dpi", "72", type=str)
    result = _send_command({"action": "screenshot", "args": {"dpi": int(dpi)}})
    if "error" in result:
        return jsonify(result), 500

    png_path = result.get("path")
    if png_path and os.path.exists(png_path):
        return app.send_static_file(png_path) if False else \
            (open(png_path, "rb").read(), 200, {"Content-Type": "image/png"})

    return jsonify({"error": "Screenshot not generated"}), 500


if __name__ == "__main__":
    DESIGNS_DIR.mkdir(parents=True, exist_ok=True)
    app.run(host="0.0.0.0", port=int(os.environ.get("BRIDGE_PORT", 8765)))
