#!/usr/bin/env python3
from flask import Flask, send_from_directory, jsonify, request, make_response
import os
import json
import requests
import subprocess
import db
from middleware import rate_limit_middleware, access_log_middleware

app = Flask(__name__)
rate_limit_middleware(app)
access_log_middleware(app)

DASHBOARD_API_URL = "http://localhost:8791"
COMBINED_API_URL = "http://localhost:8790"
SAAS_DIR = "/home/h3r7/turf_saas"

# ─── SaaS Auth & API v1 blueprints ────────────────────────────────────────────
try:
    from saas_auth import auth_bp
    from saas_api_v1 import api_v1_bp

    app.register_blueprint(auth_bp)
    app.register_blueprint(api_v1_bp)
    print("[portal] SaaS auth & API v1 blueprints registered ✅")
except Exception as e:
    print(f"[portal] Warning: could not register SaaS blueprints: {e}")


# ─── Landing & SaaS pages ─────────────────────────────────────────────────────


@app.route("/health")
def health():
    """Health check endpoint for Docker/load balancer. Returns 200 if app is running."""
    return {"status": "ok", "service": "portal"}, 200


@app.route("/")
def landing():
    """Marketing landing page."""
    return send_from_directory(SAAS_DIR, "landing.html")


@app.route("/login")
def login_page():
    return send_from_directory(SAAS_DIR, "login.html")


@app.route("/register")
def register_page():
    return send_from_directory(SAAS_DIR, "register.html")


@app.route("/dashboard")
def dashboard_saas():
    return send_from_directory(SAAS_DIR, "dashboard_saas.html")


@app.route("/onboarding")
def onboarding():
    return send_from_directory(SAAS_DIR, "onboarding.html")


@app.route("/account")
def account():
    return send_from_directory(SAAS_DIR, "account.html")


@app.route("/portal")
@app.route("/portail")
def portal_legacy():
    """Legacy portal redirect."""
    return send_from_directory(SAAS_DIR, "portail.html")


@app.route("/favicon.ico")
def favicon():
    return send_from_directory(SAAS_DIR, "favicon.ico")


@app.route("/prompts", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
@app.route("/prompts/", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
@app.route("/prompts/<path:subpath>", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
def proxy_prompts(subpath=""):
    PROMPTS_API_URL = "http://localhost:8781"
    full_url = PROMPTS_API_URL + ("/" + subpath if subpath else "/")
    if request.query_string:
        full_url += "?" + request.query_string.decode()
    try:
        headers = {
            k: v
            for k, v in request.headers
            if k.lower()
            not in ("host", "content-length", "transfer-encoding", "connection")
        }
        raw_body = request.get_data()
        resp = requests.request(
            request.method,
            full_url,
            headers=headers,
            data=raw_body,
            cookies=request.cookies,
            allow_redirects=False,
            timeout=10,
        )
        if resp.status_code in (301, 302, 303, 307, 308):
            location = resp.headers.get("Location", "")
            if location.startswith("/") and not location.startswith("/prompts"):
                location = "/prompts" + location
            r = make_response(b"", resp.status_code)
            r.headers["Location"] = location
            return r
        response = make_response(resp.content, resp.status_code)
        for k, v in resp.headers.items():
            if k.lower() not in ("content-encoding", "transfer-encoding", "connection"):
                response.headers[k] = v
        return response
    except Exception as e:
        return f"Erreur proxy prompts: {e}", 502


@app.route("/business")
def business():
    return send_from_directory("/home/h3r7/depenses_trello/templates", "business.html")


@app.route(
    "/depenses", methods=["GET", "POST", "PUT", "DELETE", "PATCH"], strict_slashes=False
)
@app.route(
    "/depenses/",
    methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
    strict_slashes=False,
)
@app.route(
    "/depenses/<path:subpath>", methods=["GET", "POST", "PUT", "DELETE", "PATCH"]
)
def proxy_depenses(subpath=""):
    backend_url = "http://localhost:8769"
    if subpath:
        full_url = f"{backend_url}/{subpath}"
    else:
        full_url = backend_url

    if request.query_string:
        full_url += "?" + request.query_string.decode()

    try:
        print(f"[DEPENSES PROXY] {request.method} {full_url}")

        # Transmettre les headers bruts sans reparser
        headers = {
            k: v
            for k, v in request.headers
            if k.lower()
            not in ("host", "content-length", "transfer-encoding", "connection")
        }

        # Body brut transmis tel quel — Content-Type préservé
        raw_body = request.get_data()

        resp = requests.request(
            request.method,
            full_url,
            headers=headers,
            data=raw_body,
            cookies=request.cookies,
            allow_redirects=False,
            timeout=10,
        )
        print(f"[DEPENSES PROXY] resp={resp.status_code}")

        if resp.status_code in (301, 302, 303, 307, 308):
            location = resp.headers.get("Location", "")
            if location.startswith("/") and not location.startswith("/depenses"):
                location = "/depenses" + location
            response = make_response(b"", resp.status_code)
            response.headers["Location"] = location
            response.headers["Content-Length"] = "0"
            return response

        if resp.status_code >= 400:
            return resp.content, resp.status_code

        response = make_response(resp.content, resp.status_code)
        for k, v in resp.headers.items():
            if k.lower() not in ("content-encoding", "transfer-encoding", "connection"):
                response.headers[k] = v
        return response
    except Exception as e:
        return f"Erreur proxy depenses: {e}", 502


@app.route("/skills", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
@app.route("/skills/", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
@app.route("/skills/<path:subpath>", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
def proxy_skills(subpath=""):
    SKILLS_API_URL = "http://localhost:8772"
    full_url = SKILLS_API_URL + ("/" + subpath if subpath else "/")
    if request.query_string:
        full_url += "?" + request.query_string.decode()
    try:
        headers = {
            k: v
            for k, v in request.headers
            if k.lower()
            not in ("host", "content-length", "transfer-encoding", "connection")
        }
        raw_body = request.get_data()
        resp = requests.request(
            request.method,
            full_url,
            headers=headers,
            data=raw_body,
            cookies=request.cookies,
            allow_redirects=False,
            timeout=10,
        )
        if resp.status_code in (301, 302, 303, 307, 308):
            location = resp.headers.get("Location", "")
            if location.startswith("/") and not location.startswith("/skills"):
                location = "/skills" + location
            r = make_response(b"", resp.status_code)
            r.headers["Location"] = location
            return r
        response = make_response(resp.content, resp.status_code)
        for k, v in resp.headers.items():
            if k.lower() not in ("content-encoding", "transfer-encoding", "connection"):
                response.headers[k] = v
        return response
    except Exception as e:
        return f"Erreur proxy skills: {e}", 502


@app.route("/crm", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
@app.route("/crm/", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
@app.route("/crm/<path:subpath>", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
def proxy_crm(subpath=""):
    CRM_API_URL = "http://localhost:8770"
    full_url = CRM_API_URL + ("/" + subpath if subpath else "/")
    if request.query_string:
        full_url += "?" + request.query_string.decode()
    try:
        headers = {
            k: v
            for k, v in request.headers
            if k.lower()
            not in ("host", "content-length", "transfer-encoding", "connection")
        }
        raw_body = request.get_data()
        resp = requests.request(
            request.method,
            full_url,
            headers=headers,
            data=raw_body,
            cookies=request.cookies,
            allow_redirects=False,
            timeout=10,
        )
        if resp.status_code in (301, 302, 303, 307, 308):
            location = resp.headers.get("Location", "")
            if location.startswith("/") and not location.startswith("/crm"):
                location = "/crm" + location
            r = make_response(b"", resp.status_code)
            r.headers["Location"] = location
            return r
        response = make_response(resp.content, resp.status_code)
        for k, v in resp.headers.items():
            if k.lower() not in ("content-encoding", "transfer-encoding", "connection"):
                response.headers[k] = v
        return response
    except Exception as e:
        return f"Erreur proxy crm: {e}", 502


@app.route("/gitea", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
@app.route("/gitea/", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
@app.route("/gitea/<path:subpath>", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
def proxy_gitea(subpath=""):
    GITEA_API_URL = "http://localhost:3000"
    full_url = GITEA_API_URL + ("/" + subpath if subpath else "/")
    if request.query_string:
        full_url += "?" + request.query_string.decode()
    try:
        headers = {
            k: v
            for k, v in request.headers
            if k.lower()
            not in ("host", "content-length", "transfer-encoding", "connection")
        }
        raw_body = request.get_data()
        resp = requests.request(
            request.method,
            full_url,
            headers=headers,
            data=raw_body,
            cookies=request.cookies,
            allow_redirects=False,
            timeout=10,
        )
        if resp.status_code in (301, 302, 303, 307, 308):
            location = resp.headers.get("Location", "")
            if location.startswith("/") and not location.startswith("/gitea"):
                location = "/gitea" + location
            r = make_response(b"", resp.status_code)
            r.headers["Location"] = location
            return r
        response = make_response(resp.content, resp.status_code)
        for k, v in resp.headers.items():
            if k.lower() not in ("content-encoding", "transfer-encoding", "connection"):
                response.headers[k] = v
        return response
    except Exception as e:
        return f"Erreur proxy gitea: {e}", 502


@app.route("/boite_a_idees.html")
def boite_a_idees():
    return send_from_directory("/home/h3r7/depenses_trello", "boite_a_idees.html")


@app.route("/niches_business.html")
def niches_business():
    return send_from_directory("/home/h3r7/depenses_trello/templates", "business.html")


@app.route("/template_restaurant_json.html")
def template_restaurant():
    return send_from_directory("/home/h3r7/turf_saas", "template_restaurant_json.html")


@app.route("/template_boulangerie_final.html")
def template_boulangerie():
    return send_from_directory(
        "/home/h3r7/turf_saas", "template_boulangerie_final.html"
    )


@app.route("/template_artisan_final.html")
def template_artisan():
    return send_from_directory("/home/h3r7/turf_saas", "template_artisan_final.html")


@app.route("/template_restaurant_final.html")
def template_restaurant_final():
    return send_from_directory("/home/h3r7/turf_saas", "template_restaurant_final.html")


@app.route("/template_complet.html")
def template_complet():
    return send_from_directory("/home/h3r7/turf_saas", "template_complet.html")


@app.route("/boite_a_idees_dashboard")
def boite_a_idees_dashboard():
    return send_from_directory("/home/h3r7/turf_saas", "boite_a_idees_dashboard.html")


@app.route("/datagouv_explorer.html")
def datagouv_explorer():
    return send_from_directory("/home/h3r7/turf_saas", "datagouv_explorer.html")


@app.route("/api_datagouv_reference.html")
def api_datagouv_reference():
    return send_from_directory("/home/h3r7/turf_saas", "api_datagouv_reference.html")


# Agent IA - Page principale
@app.route("/agent-ia")
@app.route("/agent-ia/")
def agent_ia():
    return send_from_directory("/home/h3r7/turf_saas", "agent_ia.html")


# Agent IA - Page de config
@app.route("/agent-ia/config")
@app.route("/agent-ia/config/")
def agent_ia_config():
    return send_from_directory("/home/h3r7/turf_saas", "agent_ia_config.html")


# Ancienne page (compatibilité)
@app.route("/agent-ia/legacy")
def agent_ia_legacy():
    return send_from_directory("/home/h3r7/turf_saas", "gemini_agent.html")


# --- API Chat ---


@app.route("/api/chat/workflows", methods=["GET"])
def api_chat_workflows():
    try:
        workflows = db.get_workflows()
        return jsonify([dict(w) for w in workflows])
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@app.route("/api/chat/nvidia-models", methods=["GET"])
def api_nvidia_models():
    return jsonify(
        [
            {
                "id": k,
                "name": v.split("/")[-1]
                .replace("-instruct", "")
                .replace("-", " ")
                .title(),
                "full_id": v,
            }
            for k, v in NVIDIA_MODELS.items()
        ]
    )


@app.route("/api/chat/sessions", methods=["GET"])
def api_chat_sessions():
    workflow_slug = request.args.get("workflow")
    if not workflow_slug:
        return jsonify({"error": "Paramètre workflow requis"}), 400
    try:
        sessions = db.get_sessions(workflow_slug)
        return jsonify([dict(s) for s in sessions])
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@app.route("/api/chat/history", methods=["GET"])
def api_chat_history():
    session_id = request.args.get("session_id")
    workflow_slug = request.args.get("workflow")
    if not session_id or not workflow_slug:
        return jsonify({"error": "session_id et workflow requis"}), 400
    try:
        messages = db.get_messages(session_id, workflow_slug)
        return jsonify([dict(m) for m in messages])
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@app.route("/api/chat/search", methods=["GET"])
def api_chat_search():
    query = request.args.get("q")
    workflow_slug = request.args.get("workflow")
    if not query or not workflow_slug:
        return jsonify({"error": "q et workflow requis"}), 400
    try:
        results = db.search_messages(query, workflow_slug)
        return jsonify([dict(r) for r in results])
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@app.route("/api/chat/session", methods=["POST"])
def api_chat_session_create():
    data = request.json or {}
    session_id = data.get("session_id")
    workflow_slug = data.get("workflow")
    title = data.get("title")
    if not session_id or not workflow_slug:
        return jsonify({"error": "session_id et workflow requis"}), 400
    try:
        workflows = db.get_workflows()
        wf = next((w for w in workflows if w["slug"] == workflow_slug), None)
        if not wf:
            return jsonify({"error": "Workflow introuvable"}), 404
        db.create_session(session_id, wf["id"], title)
        return jsonify({"status": "ok", "session_id": session_id})
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@app.route("/api/chat/session", methods=["PUT"])
def api_chat_session_rename():
    data = request.json or {}
    session_id = request.args.get("session_id")
    workflow_slug = request.args.get("workflow")
    new_title = data.get("title")
    if not session_id or not workflow_slug:
        return jsonify({"error": "session_id et workflow requis"}), 400
    try:
        db.rename_session(session_id, workflow_slug, new_title)
        return jsonify({"status": "ok"})
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@app.route("/api/chat/session", methods=["DELETE"])
def api_chat_session_delete():
    session_id = request.args.get("session_id")
    workflow_slug = request.args.get("workflow")
    if not session_id or not workflow_slug:
        return jsonify({"error": "session_id et workflow requis"}), 400
    try:
        deleted = db.delete_session(session_id, workflow_slug)
        return jsonify({"status": "ok", "deleted": deleted})
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@app.route("/api/chat/cleanup", methods=["POST"])
def api_chat_cleanup():
    data = request.json or {}
    days = data.get("days")
    workflow_slug = data.get("workflow")
    if not days or not workflow_slug:
        return jsonify({"error": "days et workflow requis"}), 400
    try:
        deleted = db.delete_messages_before(days, workflow_slug)
        return jsonify({"status": "ok", "deleted": deleted})
    except Exception as e:
        return jsonify({"error": str(e)}), 500


# --- Webhook proxy avec persistance ---

OPENCLAW_TOKEN = "szDd75yG15ZRADWEhGus3dfNoQve7ZhdxpGq9gudeEzoVhUqB0TomVJd90XcwkUz"
OPENCLAW_CONTAINER = "openclaw-ow404080wwkkgkgc4oswwssc"
NVIDIA_API_KEY = (
    "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"
)
NVIDIA_API_URL = "https://integrate.api.nvidia.com/v1/chat/completions"
NVIDIA_MODEL = "meta/llama-3.1-8b-instruct"  # Default model
NVIDIA_MODELS = {
    "llama-3.1-8b": "meta/llama-3.1-8b-instruct",
    "llama-3.1-70b": "meta/llama-3.1-70b-instruct",
    "llama-3.3-70b": "meta/llama-3.3-70b-instruct",
    "llama-4-scout": "meta/llama-4-scout-17b-16e-instruct",
    "nemotron-mini": "nvidia/nemotron-mini-4b-instruct",
    "nemotron-super": "nvidia/llama-3.3-nemotron-super-49b-v1",
    "mistral-small": "mistralai/mistral-small-3.1-24b-instruct-2503",
    "mistral-medium": "mistralai/mistral-medium-3-instruct",
    "mistral-large": "mistralai/mistral-large-3-675b-instruct-2512",
    "qwen-coder": "qwen/qwen3-coder-480b-a35b-instruct",
    "gemma-3": "google/gemma-3-27b-it",
    "deepseek": "deepseek-ai/deepseek-v3.2",
}


@app.route("/webhook/telegram", methods=["POST"])
def telegram_webhook():
    try:
        data = request.get_data()
        resp = requests.post(
            "http://localhost:5003/webhook",
            data=data,
            headers={"Content-Type": "application/json"},
            timeout=30,
        )
        return resp.content, resp.status_code
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@app.route("/webhook/<workflow_slug>", methods=["POST"])
def webhook_proxy(workflow_slug):
    try:
        workflows = db.get_workflows()
        wf = next((w for w in workflows if w["slug"] == workflow_slug), None)
        if not wf:
            return jsonify({"error": f'Workflow "{workflow_slug}" introuvable'}), 404

        session_id = request.headers.get("X-Session-ID", "default")
        user_message = request.json.get("message", "")

        db.create_session(session_id, wf["id"])
        db.save_message(session_id, wf["id"], "user", user_message)

        mode = wf.get("mode", "n8n")

        if mode == "direct":
            # OpenClaw gateway bind sur 127.0.0.1 uniquement → docker exec
            import subprocess

            escaped_msg = user_message.replace('"', '\\"').replace("\n", "\\n")
            cmd = [
                "docker",
                "exec",
                OPENCLAW_CONTAINER,
                "curl",
                "-s",
                "http://127.0.0.1:18789/v1/chat/completions",
                "-H",
                "Content-Type: application/json",
                "-H",
                f"Authorization: Bearer {OPENCLAW_TOKEN}",
                "-d",
                f'{{"model":"openclaw","messages":[{{"role":"user","content":"{escaped_msg}"}}],"max_tokens":4096,"temperature":0.7}}',
            ]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
            if result.returncode != 0:
                raise Exception(f"docker exec failed: {result.stderr}")
            data = json.loads(result.stdout)
            ai_response = (
                data.get("choices", [{}])[0]
                .get("message", {})
                .get("content", str(data))
            )
        elif mode == "nvidia":
            # Appel direct a l API Nvidia NIM
            # Recuperer le modele choisi (par defaut: llama-3.1-8b)
            model_key = request.json.get("model", "llama-3.1-8b")
            model_id = NVIDIA_MODELS.get(model_key, NVIDIA_MODEL)
            resp = requests.post(
                NVIDIA_API_URL,
                headers={
                    "Authorization": f"Bearer {NVIDIA_API_KEY}",
                    "Content-Type": "application/json",
                },
                json={
                    "model": model_id,
                    "messages": [{"role": "user", "content": user_message}],
                    "max_tokens": 1024,
                    "temperature": 0.7,
                },
                timeout=60,
            )
            data = resp.json()
            ai_response = (
                data.get("choices", [{}])[0]
                .get("message", {})
                .get("content", str(data))
            )
        else:
            # Proxy vers webhook n8n
            resp = requests.post(
                wf["webhook_url"],
                headers={
                    "Content-Type": "application/json",
                    "X-Session-ID": session_id,
                },
                json=request.json,
                timeout=60,
            )
            ai_response = resp.text

        db.save_message(session_id, wf["id"], "ai", ai_response)
        return ai_response, 200, {"Content-Type": "text/plain; charset=utf-8"}
    except Exception as e:
        return str(e), 500


# --- Anciens webhooks (compatibilité) ---


@app.route("/webhook/gemini-agent", methods=["POST"])
def webhook_proxy_legacy_gemini():
    return webhook_proxy("llm-models")


@app.route("/webhook/openclaw-web", methods=["POST"])
def webhook_proxy_legacy_openclaw():
    return webhook_proxy("openclaw")


TELEGRAM_TOKEN = "8649773134:AAFqzZVtSHfPPFDadcte1B-1h23nZ8DmdYE"


@app.route("/webhook/telegram-opencode", methods=["POST"])
def webhook_proxy_telegram():
    """Handle Telegram messages directly"""
    try:
        data = request.get_json(force=True, silent=True)

        print(f"[TELEGRAM] Raw: {request.data}")
        print(f"[TELEGRAM] Remote: {request.remote_addr}")
        print(f"[TELEGRAM] Headers: {request.headers.get('X-Forwarded-For', 'none')}")

        if not data:
            return jsonify({"error": "No data", "raw": request.data.decode()}), 400

        # Accept both direct message and Telegram update format
        message = data.get("message") or data.get("update", {}).get("message")

        if not message:
            return jsonify({"data": data, "keys": list(data.keys())}), 400

        chat_id = message["chat"]["id"]
        text = message.get("text", "")
        user_id = message["from"]["id"]

        if text.startswith("/start"):
            reply = "🤖 *OpencdPilot Bot*\n\nPilotez OpenCode depuis Telegram!"
        elif text.startswith("/help"):
            reply = "*Commandes:*\n/start - Démarrer\n/help - Aide\n/status - Statut"
        elif text.startswith("/status"):
            reply = "✅ *Système actif*\n- OpenCode: OK\n- Bot: OK"
        else:
            # Call OpenCode API
            opencode_resp = requests.post(
                "http://localhost:8792/api/opencode", json={"prompt": text}, timeout=180
            )
            opencode_data = opencode_resp.json()
            reply = opencode_data.get("output", opencode_data.get("error", "Erreur"))[
                :4000
            ]

        # Send reply
        requests.post(
            f"https://api.telegram.org/bot{TELEGRAM_TOKEN}/sendMessage",
            json={"chat_id": chat_id, "text": reply, "parse_mode": "Markdown"},
        )

        return jsonify({"ok": True})
    except Exception as e:
        print(f"[TELEGRAM] Error: {e}")
        return jsonify({"error": str(e)}), 500


# --- Turf Dashboard ---


@app.route("/dashboard")
@app.route("/dashboard.html")
def dashboard():
    return send_from_directory("/home/h3r7/turf_saas", "dashboard_system.html")


@app.route("/turf/")
@app.route("/turf")
def turf_index():
    return send_from_directory("/home/h3r7/turf_saas", "dashboard.html")


@app.route("/turf/<path:filename>")
def turf_static(filename):
    return send_from_directory("/home/h3r7/turf_saas", filename)


# --- POD Routes ---
@app.route("/pod/")
@app.route("/pod/<path:filename>")
def pod_static(filename=""):
    return send_from_directory(
        "/home/h3r7/turf_saas/POD", filename if filename else "pod_manager.html"
    )


@app.route("/turf/api")
@app.route("/turf/api/")
@app.route("/turf/api/<path:api_path>")
def api_proxy(api_path=""):
    # Routes servies par combined_api.py (port 8790) :
    # backtest, stats, paris, parisroi, races, scores, report, ask, brave-search,
    # execute-sql, send-email, vitesse, n8n-proxy, predictions_analysis, ideas
    # Fix HRT-73 : alignement complet avec turf_scraper fix #23
    COMBINED_ROUTES = (
        "backtest",
        "stats",
        "parisroi",
        "paris",
        "predictions_analysis",
        "vitesse",
        "n8n-proxy",
        "races",
        "race/",
        "scores",
        "ask",
        "brave-search",
        "execute-sql",
        "send-email",
        "report",
        "ideas",
    )
    if any(api_path.startswith(r) for r in COMBINED_ROUTES):
        url = f"{COMBINED_API_URL}/turf/api/{api_path}"
    elif api_path.startswith("scoring"):
        url = f"{DASHBOARD_API_URL}/turf/api/{api_path}"
    elif api_path:
        url = f"{DASHBOARD_API_URL}/turf/api/{api_path}"
    else:
        url = f"{DASHBOARD_API_URL}/turf/api"
    try:
        fwd_method = request.method
        fwd_json = (
            request.get_json(silent=True)
            if fwd_method in ("POST", "PUT", "PATCH")
            else None
        )
        # Forwarder Authorization header (combined_api.py exige Basic h3r7:h3r7 pour parisroi/paris)
        fwd_headers = {"Content-Type": "application/json"}
        incoming_auth = request.headers.get("Authorization")
        if incoming_auth:
            fwd_headers["Authorization"] = incoming_auth
        resp = requests.request(
            method=fwd_method,
            url=url,
            json=fwd_json,
            timeout=30,
            headers=fwd_headers,
        )
        return resp.content, resp.status_code, {"Content-Type": "application/json"}
    except Exception as e:
        return jsonify({"error": str(e), "url": url}), 500


@app.route("/api/opencode", methods=["POST"])
def opencode_api():
    """Execute OpenCode commands via API"""
    try:
        data = request.get_json()
        prompt = data.get("prompt", "")
        if not prompt:
            return jsonify({"error": "No prompt provided"}), 400

        # Execute opencode with the wrapper script
        result = subprocess.run(
            ["/home/h3r7/opencode_wrapper.sh", prompt],
            cwd="/home/h3r7",
            capture_output=True,
            text=True,
            timeout=180,
        )

        return jsonify(
            {
                "output": result.stdout,
                "error": result.stderr,
                "returncode": result.returncode,
            }
        )
    except subprocess.TimeoutExpired:
        return jsonify({"error": "Timeout"}), 504
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@app.route("/candidatures/")
def candidatures_index():
    return send_from_directory("/home/h3r7/turf_saas", "crm_candidatures.html")


@app.route("/candidatures/<path:filename>")
def candidatures_static(filename):
    return send_from_directory("/home/h3r7/turf_saas", filename)


@app.route("/map")
def map_visual():
    return send_from_directory("/home/h3r7/turf_saas", "map_visual.html")


@app.route("/architecture.json")
def architecture_json():
    return send_from_directory("/home/h3r7/turf_saas", "architecture.json")


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8792, debug=False)


# Telegram Bot Webhook Proxy
def telegram_webhook():
    """Proxy Telegram webhook to bot service"""
    try:
        data = request.get_data()
        resp = requests.post(
            "http://localhost:5003/webhook",
            data=data,
            headers={"Content-Type": "application/json"},
            timeout=30,
        )
        return resp.content, resp.status_code
    except Exception as e:
        return jsonify({"error": str(e)}), 500


PROMPTS_API_URL = "http://localhost:8781"


@app.route("/testprompts", methods=["GET", "POST", "PUT", "DELETE", "PATCH"])
def proxy_prompts_test():
    return "TEST_PROMPTS_OK"
    full_url = PROMPTS_API_URL + ("/" + subpath if subpath else "/")
    if request.query_string:
        full_url += "?" + request.query_string.decode()
    try:
        headers = {
            k: v
            for k, v in request.headers
            if k.lower()
            not in (
                "host",
                "content-length",
                "transfer-encoding",
                "connection",
                "authorization",
            )
        }
        raw_body = request.get_data()
        resp = requests.request(
            request.method,
            full_url,
            headers=headers,
            data=raw_body,
            cookies=request.cookies,
            allow_redirects=False,
            timeout=10,
        )
        if resp.status_code in (301, 302, 303, 307, 308):
            location = resp.headers.get("Location", "")
            if location.startswith("/") and not location.startswith("/prompts"):
                location = "/prompts" + location
            r = make_response(b"", resp.status_code)
            r.headers["Location"] = location
            return r
        response = make_response(resp.content, resp.status_code)
        for k, v in resp.headers.items():
            if k.lower() not in ("content-encoding", "transfer-encoding", "connection"):
                response.headers[k] = v
        return response
    except Exception as e:
        return f"Erreur proxy prompts: {e}", 502
