"""MercadoLibre external marketplace REST endpoints.

Routes:
  Config
    GET  /pos/api/marketplace-ext/config
    POST /pos/api/marketplace-ext/connect
    DELETE /pos/api/marketplace-ext/connect
    GET  /pos/api/marketplace-ext/categories

  Listings
    GET  /pos/api/marketplace-ext/listings
    POST /pos/api/marketplace-ext/listings
    POST /pos/api/marketplace-ext/listings/<id>/sync
    POST /pos/api/marketplace-ext/listings/<id>/pause
    POST /pos/api/marketplace-ext/listings/<id>/activate
    DELETE /pos/api/marketplace-ext/listings/<id>

  Orders
    GET  /pos/api/marketplace-ext/orders
    GET  /pos/api/marketplace-ext/orders/<id>
    POST /pos/api/marketplace-ext/orders/<id>/convert

  Webhook (public)
    POST /pos/api/marketplace-ext/webhook/meli
"""

import urllib.parse

from flask import Blueprint, request, jsonify, g
from middleware import require_auth, has_permission
from tenant_db import get_tenant_conn, get_master_conn
from services import marketplace_external_service as meli_svc


def _get_public_base_url() -> str:
    """Build the tenant's public base URL from request headers (handles reverse proxy)."""
    proto = request.headers.get("X-Forwarded-Proto", request.scheme)
    host = request.headers.get("X-Forwarded-Host", request.host)

    # Cloudflare specific header
    cf_visitor = request.headers.get("CF-Visitor")
    if cf_visitor and '"scheme":"https"' in cf_visitor:
        proto = "https"

    # Force https for production domain if we detect http behind a TLS terminator
    if proto == "http" and ("nexusautoparts.com.mx" in host or request.headers.get("X-Forwarded-Ssl") == "on"):
        proto = "https"

    return f"{proto}://{host}/"
from services.meli_service import MeliService, MeliAuthError

marketplace_ext_bp = Blueprint(
    "marketplace_ext", __name__, url_prefix="/pos/api/marketplace-ext"
)


# ─── Helpers ───────────────────────────────────────────────────────────────

def _require_meli_manage():
    if not has_permission("marketplace.manage"):
        return jsonify({"error": "Missing permission: marketplace.manage"}), 403
    return None


# ═══════════════════════════════════════════════════════════════════════════
# CONFIG
# ═══════════════════════════════════════════════════════════════════════════

@marketplace_ext_bp.route("/config", methods=["GET"])
@require_auth()
def get_config():
    conn = get_tenant_conn(g.tenant_id)
    try:
        cfg = meli_svc.get_meli_config(conn)
        # Never return tokens to frontend
        safe = {
            k: v for k, v in cfg.items()
            if k not in ("meli_access_token", "meli_refresh_token", "meli_client_secret")
        }
        safe["connected"] = bool(cfg.get("meli_access_token"))
        return jsonify(safe)
    finally:
        conn.close()


@marketplace_ext_bp.route("/connect/init", methods=["POST"])
@require_auth()
def init_meli_connect():
    """Store client credentials server-side and return the MercadoLibre auth URL.

    The frontend no longer keeps the client_secret in localStorage.
    """
    err = _require_meli_manage()
    if err:
        return err

    data = request.get_json() or {}
    client_id = data.get("client_id", "").strip()
    client_secret = data.get("client_secret", "").strip()
    category = data.get("category", "").strip()
    shipping = data.get("shipping", "").strip()

    if not client_id or not client_secret:
        return jsonify({"error": "client_id and client_secret required"}), 400

    base = _get_public_base_url().rstrip("/")
    redirect_uri = f"{base}/pos/marketplace-external/callback"

    conn = get_tenant_conn(g.tenant_id)
    try:
        meli_svc.save_meli_config(conn, {
            "meli_client_id": client_id,
            "meli_client_secret": client_secret,
            "meli_default_category_id": category,
            "meli_shipping_mode": shipping,
        })
    finally:
        conn.close()

    auth_url = (
        "https://auth.mercadolibre.com.mx/authorization?response_type=code"
        f"&client_id={urllib.parse.quote(client_id)}"
        f"&redirect_uri={urllib.parse.quote(redirect_uri)}"
        "&scope=read+write+offline_access"
    )
    return jsonify({"auth_url": auth_url, "redirect_uri": redirect_uri})


@marketplace_ext_bp.route("/connect", methods=["POST"])
@require_auth()
def connect_meli():
    err = _require_meli_manage()
    if err:
        return err

    data = request.get_json() or {}
    code = data.get("code")
    redirect_uri = data.get("redirect_uri", "")

    if not code:
        return jsonify({"error": "code required"}), 400

    conn = get_tenant_conn(g.tenant_id)
    try:
        cfg = meli_svc.get_meli_config(conn)
        client_id = data.get("client_id") or cfg.get("meli_client_id")
        client_secret = data.get("client_secret") or cfg.get("meli_client_secret")
    finally:
        conn.close()

    if not client_id or not client_secret:
        return jsonify({"error": "ML credentials not configured"}), 400

    try:
        token_data = MeliService.exchange_code(code, client_id, client_secret, redirect_uri)
    except MeliAuthError as e:
        return jsonify({"error": str(e)}), 400

    access_token = token_data.get("access_token")
    refresh_token = token_data.get("refresh_token")
    user_id = token_data.get("user_id")

    # Validate token by fetching user
    svc = MeliService(access_token)
    try:
        user = svc.get_user()
    except MeliAuthError as e:
        return jsonify({"error": f"Invalid token: {e}"}), 400

    conn = get_tenant_conn(g.tenant_id)
    try:
        meli_svc.save_meli_config(conn, {
            "meli_access_token": access_token,
            "meli_refresh_token": refresh_token,
            "meli_user_id": str(user_id or user.get("id")),
            "meli_site_id": user.get("site_id", "MLM"),
            "meli_enabled": "true",
            "meli_client_id": client_id,
            "meli_client_secret": client_secret,
        })
        return jsonify({
            "ok": True,
            "user_id": user_id or user.get("id"),
            "nickname": user.get("nickname"),
            "site_id": user.get("site_id"),
        })
    finally:
        conn.close()


@marketplace_ext_bp.route("/connect", methods=["DELETE"])
@require_auth()
def disconnect_meli():
    err = _require_meli_manage()
    if err:
        return err

    conn = get_tenant_conn(g.tenant_id)
    try:
        meli_svc.delete_meli_config(conn)
        return jsonify({"ok": True})
    finally:
        conn.close()


@marketplace_ext_bp.route("/categories", methods=["GET"])
@require_auth()
def search_categories():
    q = request.args.get("q", "")
    site_id = request.args.get("site_id", "MLM")
    if not q or len(q) < 2:
        return jsonify({"categories": []})

    conn = get_tenant_conn(g.tenant_id)
    try:
        cfg = meli_svc.get_meli_config(conn)
        svc = meli_svc._get_meli_service(cfg)
        if not svc:
            return jsonify({"error": "MercadoLibre not connected"}), 400
        result = svc.search_categories(site_id, q)
        return jsonify({"categories": result})
    except MeliAuthError:
        return jsonify({"error": "MercadoLibre token expired. Please reconnect."}), 401
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


# ═══════════════════════════════════════════════════════════════════════════
# LISTINGS
# ═══════════════════════════════════════════════════════════════════════════

@marketplace_ext_bp.route("/listings", methods=["GET"])
@require_auth()
def list_listings():
    page = int(request.args.get("page", 1))
    per_page = min(int(request.args.get("per_page", 50)), 200)
    status = request.args.get("status")

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.get_listings(conn, page=page, per_page=per_page, status=status)
        return jsonify(result)
    except MeliAuthError:
        return jsonify({"error": "MercadoLibre token expired. Please reconnect."}), 401
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/listings", methods=["POST"])
@require_auth()
def create_listings():
    err = _require_meli_manage()
    if err:
        return err

    data = request.get_json() or {}
    inventory_ids = data.get("inventory_ids", [])
    category_id = data.get("category_id")
    listing_type = data.get("listing_type", "gold_special")
    shipping_mode = data.get("shipping_mode", "me2")
    custom_data = data.get("custom_data", {})

    if not inventory_ids:
        return jsonify({"error": "inventory_ids required"}), 400
    if not category_id:
        return jsonify({"error": "category_id required"}), 400

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.publish_items(
            conn,
            inventory_ids=inventory_ids,
            meli_category_id=category_id,
            listing_type_id=listing_type,
            shipping_mode=shipping_mode,
            custom_data=custom_data,
            base_url=_get_public_base_url(),
        )
        return jsonify(result), 201
    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/listings/import-existing", methods=["POST"])
@require_auth()
def import_existing_listings():
    """Import all existing MercadoLibre listings for the connected seller."""
    err = _require_meli_manage()
    if err:
        return err

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.import_existing_listings(conn)
        return jsonify(result), 200
    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/inventory-check", methods=["POST"])
@require_auth()
def inventory_check():
    """Check local pre-flight status for ML publishing (duplicates, stock, price, image)."""
    data = request.get_json() or {}
    inventory_ids = data.get("inventory_ids", [])
    if not inventory_ids:
        return jsonify({"error": "inventory_ids required"}), 400

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.check_inventory_ml_status(conn, inventory_ids, base_url=_get_public_base_url())
        return jsonify(result)
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/sync-stock", methods=["POST"])
@require_auth()
def sync_stock_to_meli():
    """Process pending stock updates to MercadoLibre."""
    err = _require_meli_manage()
    if err:
        return err

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.process_meli_sync_queue(conn)
        return jsonify(result)
    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/categories/<category_id>/attributes", methods=["GET"])
@require_auth()
def category_attributes(category_id):
    """Get required attributes for a MercadoLibre category."""
    conn = get_tenant_conn(g.tenant_id)
    try:
        cfg = meli_svc.get_meli_config(conn)
        svc = meli_svc._get_meli_service(cfg)
        if not svc:
            return jsonify({"error": "MercadoLibre not connected"}), 400
        attrs = svc.get_category_attributes(category_id)
        # Filter to required attributes only for the UI
        required = [a for a in attrs if a.get("tags", {}).get("required")]
        return jsonify({"attributes": required, "all": attrs})
    except MeliAuthError:
        return jsonify({"error": "MercadoLibre token expired. Please reconnect."}), 401
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/listings/validate", methods=["POST"])
@require_auth()
def validate_listings():
    """Validate items payload against ML /items/validate without creating them."""
    err = _require_meli_manage()
    if err:
        return err

    data = request.get_json() or {}
    inventory_ids = data.get("inventory_ids", [])
    category_id = data.get("category_id")
    listing_type = data.get("listing_type", "gold_special")
    shipping_mode = data.get("shipping_mode", "me2")
    custom_data = data.get("custom_data", {})

    if not inventory_ids:
        return jsonify({"error": "inventory_ids required"}), 400
    if not category_id:
        return jsonify({"error": "category_id required"}), 400

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.validate_items(
            conn,
            inventory_ids=inventory_ids,
            meli_category_id=category_id,
            listing_type_id=listing_type,
            shipping_mode=shipping_mode,
            custom_data=custom_data,
            base_url=_get_public_base_url(),
        )
        return jsonify(result)
    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/listings/async", methods=["POST"])
@require_auth()
def create_listings_async():
    """Enqueue ML publishing as a Celery background task."""
    err = _require_meli_manage()
    if err:
        return err

    data = request.get_json() or {}
    inventory_ids = data.get("inventory_ids", [])
    category_id = data.get("category_id")
    listing_type = data.get("listing_type", "gold_special")
    shipping_mode = data.get("shipping_mode", "me2")
    custom_data = data.get("custom_data", {})

    if not inventory_ids:
        return jsonify({"error": "inventory_ids required"}), 400
    if not category_id:
        return jsonify({"error": "category_id required"}), 400

    try:
        from tasks import publish_meli_items_task
        task = publish_meli_items_task.delay(
            g.tenant_id,
            inventory_ids=inventory_ids,
            category_id=category_id,
            listing_type=listing_type,
            shipping_mode=shipping_mode,
            custom_data=custom_data,
            base_url=_get_public_base_url(),
        )
        return jsonify({"task_id": task.id, "status": "queued"}), 202
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@marketplace_ext_bp.route("/listings/async/<task_id>", methods=["GET"])
@require_auth()
def get_async_listing_status(task_id):
    """Get status of an async ML publishing task."""
    try:
        from celery.result import AsyncResult
        from app import celery as celery_app
        result = AsyncResult(task_id, app=celery_app)
        if result.ready():
            return jsonify({"status": "done", "result": result.result or {}})
        return jsonify({"status": "pending"})
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@marketplace_ext_bp.route("/listings/<int:listing_id>/sync", methods=["POST"])
@require_auth()
def sync_listing(listing_id):
    err = _require_meli_manage()
    if err:
        return err

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.sync_listing(conn, listing_id)
        return jsonify(result)
    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/listings/<int:listing_id>/pause", methods=["POST"])
@require_auth()
def pause_listing(listing_id):
    err = _require_meli_manage()
    if err:
        return err

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.pause_listing(conn, listing_id)
        return jsonify(result)
    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/listings/<int:listing_id>/activate", methods=["POST"])
@require_auth()
def activate_listing(listing_id):
    err = _require_meli_manage()
    if err:
        return err

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.activate_listing(conn, listing_id)
        return jsonify(result)
    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/listings/<int:listing_id>", methods=["DELETE"])
@require_auth()
def delete_listing(listing_id):
    err = _require_meli_manage()
    if err:
        return err

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.close_listing(conn, listing_id)
        return jsonify(result)
    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/listings/<int:listing_id>/permanent", methods=["DELETE"])
@require_auth()
def delete_listing_permanent(listing_id):
    """Hard-delete a closed listing from the local DB."""
    err = _require_meli_manage()
    if err:
        return err

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.delete_listing_permanently(conn, listing_id)
        return jsonify(result)
    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


# ═══════════════════════════════════════════════════════════════════════════
# QUESTIONS & ANSWERS
# ═══════════════════════════════════════════════════════════════════════════

@marketplace_ext_bp.route("/questions", methods=["GET"])
@require_auth()
def list_questions():
    """List questions from local DB. Query param: ?status=unanswered"""
    status = request.args.get("status")
    conn = get_tenant_conn(g.tenant_id)
    try:
        items = meli_svc.list_local_questions(conn, status=status)
        return jsonify({"items": items})
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/questions/sync", methods=["POST"])
@require_auth()
def sync_questions():
    """Force sync questions from ML for all active listings."""
    err = _require_meli_manage()
    if err:
        return err
    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.sync_questions(conn)
        return jsonify(result)
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/questions/<int:question_id>/answer", methods=["POST"])
@require_auth()
def answer_question(question_id):
    """Answer a buyer question via ML API."""
    err = _require_meli_manage()
    if err:
        return err
    data = request.get_json() or {}
    text = data.get("text", "").strip()
    if not text:
        return jsonify({"error": "Answer text is required"}), 400
    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.answer_question(conn, question_id, text)
        return jsonify(result)
    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


# ═══════════════════════════════════════════════════════════════════════════
# ORDERS
# ═══════════════════════════════════════════════════════════════════════════

@marketplace_ext_bp.route("/orders/sync", methods=["POST"])
@require_auth()
def sync_orders():
    """Manually trigger sync of MercadoLibre orders."""
    err = _require_meli_manage()
    if err:
        return err

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.fetch_and_save_orders(conn)
        return jsonify(result)
    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/orders", methods=["GET"])
@require_auth()
def list_orders():
    page = int(request.args.get("page", 1))
    per_page = min(int(request.args.get("per_page", 50)), 200)
    status = request.args.get("status")

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.get_orders(conn, page=page, per_page=per_page, status=status)
        return jsonify(result)
    finally:
        conn.close()


@marketplace_ext_bp.route("/orders/<int:order_id>", methods=["GET"])
@require_auth()
def get_order(order_id):
    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.get_order_detail(conn, order_id)
        return jsonify(result)
    except ValueError as e:
        return jsonify({"error": str(e)}), 404
    finally:
        conn.close()


@marketplace_ext_bp.route("/orders/<int:order_id>/convert", methods=["POST"])
@require_auth("pos.sell")
def convert_order(order_id):
    data = request.get_json() or {}
    register_id = data.get("register_id")

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.convert_order_to_sale(
            conn, order_id, employee_id=g.employee_id, register_id=register_id
        )
        return jsonify(result)
    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


@marketplace_ext_bp.route("/orders/<int:order_id>/status", methods=["POST"])
@require_auth()
def update_order_status_route(order_id):
    data = request.get_json() or {}
    new_status = data.get("status")
    if not new_status:
        return jsonify({"error": "status required"}), 400

    conn = get_tenant_conn(g.tenant_id)
    try:
        result = meli_svc.update_order_status(conn, order_id, new_status)
        return jsonify(result)
    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        return jsonify({"error": str(e)}), 500
    finally:
        conn.close()


# ═══════════════════════════════════════════════════════════════════════════
# WEBHOOK (public — no auth)
# ═══════════════════════════════════════════════════════════════════════════

@marketplace_ext_bp.route("/webhook/meli", methods=["POST"])
def meli_webhook():
    """Receive MercadoLibre notifications.

    ML sends a lightweight payload with topic + resource URL.
    We ack immediately and enqueue Celery for async processing.
    """
    data = request.get_json(force=True, silent=True) or {}
    topic = data.get("topic", "")
    resource = data.get("resource", "")
    user_id = data.get("user_id")

    # Resolve tenant by meli_user_id
    tenant_id = None
    if user_id:
        try:
            mconn = get_master_conn()
            mcur = mconn.cursor()
            mcur.execute(
                """
                SELECT t.id FROM tenants t
                JOIN tenant_config c ON c.key = 'meli_user_id' AND c.value = %s
                WHERE t.is_active = true
                LIMIT 1
                """,
                (str(user_id),),
            )
            row = mcur.fetchone()
            if row:
                tenant_id = row[0]
            mcur.close()
            mconn.close()
        except Exception:
            pass

    if tenant_id and topic:
        try:
            from tasks import process_meli_webhook_task
            process_meli_webhook_task.delay(tenant_id, topic, resource)
        except Exception as e:
            print(f"[ML Webhook] Failed to enqueue task: {e}")

    return jsonify({"ok": True})
